mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-01 00:58:39 +02:00 
			
		
		
		
	arm: orion: Use generic irq chip
The core interrupt chip is a straight forward conversion. The gpio chip is implemented with two instances of the irq_chip_type which can be switched with the irq_set_type function. That allows us to use the generic callbacks and avoids the conditionals in them. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Nicolas Pitre <nico@fluxnic.net>
This commit is contained in:
		
							parent
							
								
									cfefd21e69
								
							
						
					
					
						commit
						e59347a1d1
					
				
					 3 changed files with 44 additions and 116 deletions
				
			
		|  | @ -321,59 +321,16 @@ EXPORT_SYMBOL(orion_gpio_set_blink); | |||
|  *        polarity    LEVEL          mask | ||||
|  * | ||||
|  ****************************************************************************/ | ||||
| static void gpio_irq_ack(struct irq_data *d) | ||||
| { | ||||
| 	struct orion_gpio_chip *ochip = irq_data_get_irq_chip_data(d); | ||||
| 	int type = irqd_get_trigger_type(d); | ||||
| 
 | ||||
| 	if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) { | ||||
| 		int pin = d->irq - ochip->secondary_irq_base; | ||||
| 
 | ||||
| 		writel(~(1 << pin), GPIO_EDGE_CAUSE(ochip)); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void gpio_irq_mask(struct irq_data *d) | ||||
| { | ||||
| 	struct orion_gpio_chip *ochip = irq_data_get_irq_chip_data(d); | ||||
| 	int type = irqd_get_trigger_type(d); | ||||
| 	void __iomem *reg; | ||||
| 	int pin; | ||||
| 
 | ||||
| 	if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) | ||||
| 		reg = GPIO_EDGE_MASK(ochip); | ||||
| 	else | ||||
| 		reg = GPIO_LEVEL_MASK(ochip); | ||||
| 
 | ||||
| 	pin = d->irq - ochip->secondary_irq_base; | ||||
| 
 | ||||
| 	writel(readl(reg) & ~(1 << pin), reg); | ||||
| } | ||||
| 
 | ||||
| static void gpio_irq_unmask(struct irq_data *d) | ||||
| { | ||||
| 	struct orion_gpio_chip *ochip = irq_data_get_irq_chip_data(d); | ||||
| 	int type = irqd_get_trigger_type(d); | ||||
| 	void __iomem *reg; | ||||
| 	int pin; | ||||
| 
 | ||||
| 	if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) | ||||
| 		reg = GPIO_EDGE_MASK(ochip); | ||||
| 	else | ||||
| 		reg = GPIO_LEVEL_MASK(ochip); | ||||
| 
 | ||||
| 	pin = d->irq - ochip->secondary_irq_base; | ||||
| 
 | ||||
| 	writel(readl(reg) | (1 << pin), reg); | ||||
| } | ||||
| 
 | ||||
| static int gpio_irq_set_type(struct irq_data *d, u32 type) | ||||
| { | ||||
| 	struct orion_gpio_chip *ochip = irq_data_get_irq_chip_data(d); | ||||
| 	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | ||||
| 	struct irq_chip_type *ct = irq_data_get_chip_type(d); | ||||
| 	struct orion_gpio_chip *ochip = gc->private; | ||||
| 	int pin; | ||||
| 	u32 u; | ||||
| 
 | ||||
| 	pin = d->irq - ochip->secondary_irq_base; | ||||
| 	pin = d->irq - gc->irq_base; | ||||
| 
 | ||||
| 	u = readl(GPIO_IO_CONF(ochip)) & (1 << pin); | ||||
| 	if (!u) { | ||||
|  | @ -382,18 +339,14 @@ static int gpio_irq_set_type(struct irq_data *d, u32 type) | |||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Set edge/level type. | ||||
| 	 */ | ||||
| 	if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) { | ||||
| 		__irq_set_handler_locked(d->irq, handle_edge_irq); | ||||
| 	} else if (type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) { | ||||
| 		__irq_set_handler_locked(d->irq, handle_level_irq); | ||||
| 	} else { | ||||
| 		printk(KERN_ERR "failed to set irq=%d (type=%d)\n", | ||||
| 		       d->irq, type); | ||||
| 	type &= IRQ_TYPE_SENSE_MASK; | ||||
| 	if (type == IRQ_TYPE_NONE) | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Check if we need to change chip and handler */ | ||||
| 	if (!(ct->type & type)) | ||||
| 		if (irq_setup_alt_chip(d, type)) | ||||
| 			return -EINVAL; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Configure interrupt polarity. | ||||
|  | @ -425,19 +378,12 @@ static int gpio_irq_set_type(struct irq_data *d, u32 type) | |||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| struct irq_chip orion_gpio_irq_chip = { | ||||
| 	.name		= "orion_gpio_irq", | ||||
| 	.irq_ack	= gpio_irq_ack, | ||||
| 	.irq_mask	= gpio_irq_mask, | ||||
| 	.irq_unmask	= gpio_irq_unmask, | ||||
| 	.irq_set_type	= gpio_irq_set_type, | ||||
| }; | ||||
| 
 | ||||
| void __init orion_gpio_init(int gpio_base, int ngpio, | ||||
| 			    u32 base, int mask_offset, int secondary_irq_base) | ||||
| { | ||||
| 	struct orion_gpio_chip *ochip; | ||||
| 	int i; | ||||
| 	struct irq_chip_generic *gc; | ||||
| 	struct irq_chip_type *ct; | ||||
| 
 | ||||
| 	if (orion_gpio_chip_count == ARRAY_SIZE(orion_gpio_chips)) | ||||
| 		return; | ||||
|  | @ -471,15 +417,29 @@ void __init orion_gpio_init(int gpio_base, int ngpio, | |||
| 	writel(0, GPIO_EDGE_MASK(ochip)); | ||||
| 	writel(0, GPIO_LEVEL_MASK(ochip)); | ||||
| 
 | ||||
| 	for (i = 0; i < ngpio; i++) { | ||||
| 		unsigned int irq = secondary_irq_base + i; | ||||
| 	gc = irq_alloc_generic_chip("orion_gpio_irq", 2, secondary_irq_base, | ||||
| 				    ochip->base, handle_level_irq); | ||||
| 	gc->private = ochip; | ||||
| 
 | ||||
| 		irq_set_chip_and_handler(irq, &orion_gpio_irq_chip, | ||||
| 					 handle_level_irq); | ||||
| 		irq_set_chip_data(irq, ochip); | ||||
| 		irq_set_status_flags(irq, IRQ_LEVEL); | ||||
| 		set_irq_flags(irq, IRQF_VALID); | ||||
| 	} | ||||
| 	ct = gc->chip_types; | ||||
| 	ct->regs.mask = ochip->mask_offset + GPIO_LEVEL_MASK_OFF; | ||||
| 	ct->type = IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW; | ||||
| 	ct->chip.irq_mask = irq_gc_mask_clr_bit; | ||||
| 	ct->chip.irq_unmask = irq_gc_mask_set_bit; | ||||
| 	ct->chip.irq_set_type = gpio_irq_set_type; | ||||
| 
 | ||||
| 	ct++; | ||||
| 	ct->regs.mask = ochip->mask_offset + GPIO_EDGE_MASK_OFF; | ||||
| 	ct->regs.ack = GPIO_EDGE_CAUSE_OFF; | ||||
| 	ct->type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; | ||||
| 	ct->chip.irq_ack = irq_gc_ack; | ||||
| 	ct->chip.irq_mask = irq_gc_mask_clr_bit; | ||||
| 	ct->chip.irq_unmask = irq_gc_mask_set_bit; | ||||
| 	ct->chip.irq_set_type = gpio_irq_set_type; | ||||
| 	ct->handler = handle_edge_irq; | ||||
| 
 | ||||
| 	irq_setup_generic_chip(gc, IRQ_MSK(ngpio), IRQ_GC_INIT_MASK_CACHE, | ||||
| 			       IRQ_NOREQUEST, IRQ_LEVEL | IRQ_NOPROBE); | ||||
| } | ||||
| 
 | ||||
| void orion_gpio_irq_handler(int pinoff) | ||||
|  |  | |||
|  | @ -39,7 +39,6 @@ void __init orion_gpio_init(int gpio_base, int ngpio, | |||
| /*
 | ||||
|  * GPIO interrupt handling. | ||||
|  */ | ||||
| extern struct irq_chip orion_gpio_irq_chip; | ||||
| void orion_gpio_irq_handler(int irqoff); | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -14,52 +14,21 @@ | |||
| #include <linux/io.h> | ||||
| #include <plat/irq.h> | ||||
| 
 | ||||
| static void orion_irq_mask(struct irq_data *d) | ||||
| { | ||||
| 	void __iomem *maskaddr = irq_data_get_irq_chip_data(d); | ||||
| 	u32 mask; | ||||
| 
 | ||||
| 	mask = readl(maskaddr); | ||||
| 	mask &= ~(1 << (d->irq & 31)); | ||||
| 	writel(mask, maskaddr); | ||||
| } | ||||
| 
 | ||||
| static void orion_irq_unmask(struct irq_data *d) | ||||
| { | ||||
| 	void __iomem *maskaddr = irq_data_get_irq_chip_data(d); | ||||
| 	u32 mask; | ||||
| 
 | ||||
| 	mask = readl(maskaddr); | ||||
| 	mask |= 1 << (d->irq & 31); | ||||
| 	writel(mask, maskaddr); | ||||
| } | ||||
| 
 | ||||
| static struct irq_chip orion_irq_chip = { | ||||
| 	.name		= "orion_irq", | ||||
| 	.irq_mask	= orion_irq_mask, | ||||
| 	.irq_mask_ack	= orion_irq_mask, | ||||
| 	.irq_unmask	= orion_irq_unmask, | ||||
| }; | ||||
| 
 | ||||
| void __init orion_irq_init(unsigned int irq_start, void __iomem *maskaddr) | ||||
| { | ||||
| 	unsigned int i; | ||||
| 	struct irq_chip_generic *gc; | ||||
| 	struct irq_chip_type *ct; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Mask all interrupts initially. | ||||
| 	 */ | ||||
| 	writel(0, maskaddr); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Register IRQ sources. | ||||
| 	 */ | ||||
| 	for (i = 0; i < 32; i++) { | ||||
| 		unsigned int irq = irq_start + i; | ||||
| 
 | ||||
| 		irq_set_chip_and_handler(irq, &orion_irq_chip, | ||||
| 					 handle_level_irq); | ||||
| 		irq_set_chip_data(irq, maskaddr); | ||||
| 		irq_set_status_flags(irq, IRQ_LEVEL); | ||||
| 		set_irq_flags(irq, IRQF_VALID); | ||||
| 	} | ||||
| 	gc = irq_alloc_generic_chip("orion_irq", 1, irq_start, maskaddr, | ||||
| 				    handle_level_irq); | ||||
| 	ct = gc->chip_types; | ||||
| 	ct->chip.irq_mask = irq_gc_mask_clr_bit; | ||||
| 	ct->chip.irq_unmask = irq_gc_mask_set_bit; | ||||
| 	irq_setup_generic_chip(gc, IRQ_MSK(32), IRQ_GC_INIT_MASK_CACHE, | ||||
| 			       IRQ_NOREQUEST, IRQ_LEVEL | IRQ_NOPROBE); | ||||
| } | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Thomas Gleixner
						Thomas Gleixner