forked from mirrors/linux
		
	gpio: omap: convert driver to use gpiolib irqchip
Converts the GPIO OMAP driver to register its chained irq handler and irqchip using the helpers in the gpiolib core. Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk> Tested-by: Tony Lindgren <tony@atomide.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
This commit is contained in:
		
							parent
							
								
									cd0a3748f3
								
							
						
					
					
						commit
						fb655f57ce
					
				
					 2 changed files with 52 additions and 56 deletions
				
			
		|  | @ -247,6 +247,7 @@ config GPIO_OMAP | ||||||
| 	bool "TI OMAP GPIO support" | 	bool "TI OMAP GPIO support" | ||||||
| 	default y if ARCH_OMAP | 	default y if ARCH_OMAP | ||||||
| 	depends on ARM && ARCH_OMAP | 	depends on ARM && ARCH_OMAP | ||||||
|  | 	select GPIOLIB_IRQCHIP | ||||||
| 	help | 	help | ||||||
| 	  Say yes here to enable GPIO support for TI OMAP SoCs. | 	  Say yes here to enable GPIO support for TI OMAP SoCs. | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -24,7 +24,6 @@ | ||||||
| #include <linux/pm.h> | #include <linux/pm.h> | ||||||
| #include <linux/of.h> | #include <linux/of.h> | ||||||
| #include <linux/of_device.h> | #include <linux/of_device.h> | ||||||
| #include <linux/irqdomain.h> |  | ||||||
| #include <linux/irqchip/chained_irq.h> | #include <linux/irqchip/chained_irq.h> | ||||||
| #include <linux/gpio.h> | #include <linux/gpio.h> | ||||||
| #include <linux/platform_data/gpio-omap.h> | #include <linux/platform_data/gpio-omap.h> | ||||||
|  | @ -52,7 +51,6 @@ struct gpio_bank { | ||||||
| 	struct list_head node; | 	struct list_head node; | ||||||
| 	void __iomem *base; | 	void __iomem *base; | ||||||
| 	u16 irq; | 	u16 irq; | ||||||
| 	struct irq_domain *domain; |  | ||||||
| 	u32 non_wakeup_gpios; | 	u32 non_wakeup_gpios; | ||||||
| 	u32 enabled_non_wakeup_gpios; | 	u32 enabled_non_wakeup_gpios; | ||||||
| 	struct gpio_regs context; | 	struct gpio_regs context; | ||||||
|  | @ -95,11 +93,10 @@ static int irq_to_gpio(struct gpio_bank *bank, unsigned int gpio_irq) | ||||||
| 	return bank->chip.base + gpio_irq; | 	return bank->chip.base + gpio_irq; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int omap_gpio_to_irq(struct gpio_chip *chip, unsigned offset) | static inline struct gpio_bank *_irq_data_get_bank(struct irq_data *d) | ||||||
| { | { | ||||||
| 	struct gpio_bank *bank = container_of(chip, struct gpio_bank, chip); | 	struct gpio_chip *chip = irq_data_get_irq_chip_data(d); | ||||||
| 
 | 	return container_of(chip, struct gpio_bank, chip); | ||||||
| 	return irq_find_mapping(bank->domain, offset); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input) | static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input) | ||||||
|  | @ -479,7 +476,7 @@ static int gpio_is_input(struct gpio_bank *bank, int mask) | ||||||
| 
 | 
 | ||||||
| static int gpio_irq_type(struct irq_data *d, unsigned type) | static int gpio_irq_type(struct irq_data *d, unsigned type) | ||||||
| { | { | ||||||
| 	struct gpio_bank *bank = irq_data_get_irq_chip_data(d); | 	struct gpio_bank *bank = _irq_data_get_bank(d); | ||||||
| 	unsigned gpio = 0; | 	unsigned gpio = 0; | ||||||
| 	int retval; | 	int retval; | ||||||
| 	unsigned long flags; | 	unsigned long flags; | ||||||
|  | @ -514,14 +511,6 @@ static int gpio_irq_type(struct irq_data *d, unsigned type) | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	retval = gpio_lock_as_irq(&bank->chip, offset); |  | ||||||
| 	if (retval) { |  | ||||||
| 		dev_err(bank->dev, "unable to lock offset %d for IRQ\n", |  | ||||||
| 			offset); |  | ||||||
| 		spin_unlock_irqrestore(&bank->lock, flags); |  | ||||||
| 		return retval; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	bank->irq_usage |= 1 << GPIO_INDEX(bank, gpio); | 	bank->irq_usage |= 1 << GPIO_INDEX(bank, gpio); | ||||||
| 	spin_unlock_irqrestore(&bank->lock, flags); | 	spin_unlock_irqrestore(&bank->lock, flags); | ||||||
| 
 | 
 | ||||||
|  | @ -664,7 +653,7 @@ static void _reset_gpio(struct gpio_bank *bank, int gpio) | ||||||
| /* Use disable_irq_wake() and enable_irq_wake() functions from drivers */ | /* Use disable_irq_wake() and enable_irq_wake() functions from drivers */ | ||||||
| static int gpio_wake_enable(struct irq_data *d, unsigned int enable) | static int gpio_wake_enable(struct irq_data *d, unsigned int enable) | ||||||
| { | { | ||||||
| 	struct gpio_bank *bank = irq_data_get_irq_chip_data(d); | 	struct gpio_bank *bank = _irq_data_get_bank(d); | ||||||
| 	unsigned int gpio = irq_to_gpio(bank, d->hwirq); | 	unsigned int gpio = irq_to_gpio(bank, d->hwirq); | ||||||
| 
 | 
 | ||||||
| 	return _set_gpio_wakeup(bank, gpio, enable); | 	return _set_gpio_wakeup(bank, gpio, enable); | ||||||
|  | @ -732,11 +721,12 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) | ||||||
| 	unsigned int bit; | 	unsigned int bit; | ||||||
| 	struct gpio_bank *bank; | 	struct gpio_bank *bank; | ||||||
| 	int unmasked = 0; | 	int unmasked = 0; | ||||||
| 	struct irq_chip *chip = irq_desc_get_chip(desc); | 	struct irq_chip *irqchip = irq_desc_get_chip(desc); | ||||||
|  | 	struct gpio_chip *chip = irq_get_handler_data(irq); | ||||||
| 
 | 
 | ||||||
| 	chained_irq_enter(chip, desc); | 	chained_irq_enter(irqchip, desc); | ||||||
| 
 | 
 | ||||||
| 	bank = irq_get_handler_data(irq); | 	bank = container_of(chip, struct gpio_bank, chip); | ||||||
| 	isr_reg = bank->base + bank->regs->irqstatus; | 	isr_reg = bank->base + bank->regs->irqstatus; | ||||||
| 	pm_runtime_get_sync(bank->dev); | 	pm_runtime_get_sync(bank->dev); | ||||||
| 
 | 
 | ||||||
|  | @ -764,7 +754,7 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) | ||||||
| 		configured, we could unmask GPIO bank interrupt immediately */ | 		configured, we could unmask GPIO bank interrupt immediately */ | ||||||
| 		if (!level_mask && !unmasked) { | 		if (!level_mask && !unmasked) { | ||||||
| 			unmasked = 1; | 			unmasked = 1; | ||||||
| 			chained_irq_exit(chip, desc); | 			chained_irq_exit(irqchip, desc); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (!isr) | 		if (!isr) | ||||||
|  | @ -784,7 +774,8 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) | ||||||
| 			if (bank->toggle_mask & (1 << bit)) | 			if (bank->toggle_mask & (1 << bit)) | ||||||
| 				_toggle_gpio_edge_triggering(bank, bit); | 				_toggle_gpio_edge_triggering(bank, bit); | ||||||
| 
 | 
 | ||||||
| 			generic_handle_irq(irq_find_mapping(bank->domain, bit)); | 			generic_handle_irq(irq_find_mapping(bank->chip.irqdomain, | ||||||
|  | 							    bit)); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	/* if bank has any level sensitive GPIO pin interrupt
 | 	/* if bank has any level sensitive GPIO pin interrupt
 | ||||||
|  | @ -793,13 +784,13 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) | ||||||
| 	interrupt */ | 	interrupt */ | ||||||
| exit: | exit: | ||||||
| 	if (!unmasked) | 	if (!unmasked) | ||||||
| 		chained_irq_exit(chip, desc); | 		chained_irq_exit(irqchip, desc); | ||||||
| 	pm_runtime_put(bank->dev); | 	pm_runtime_put(bank->dev); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void gpio_irq_shutdown(struct irq_data *d) | static void gpio_irq_shutdown(struct irq_data *d) | ||||||
| { | { | ||||||
| 	struct gpio_bank *bank = irq_data_get_irq_chip_data(d); | 	struct gpio_bank *bank = _irq_data_get_bank(d); | ||||||
| 	unsigned int gpio = irq_to_gpio(bank, d->hwirq); | 	unsigned int gpio = irq_to_gpio(bank, d->hwirq); | ||||||
| 	unsigned long flags; | 	unsigned long flags; | ||||||
| 	unsigned offset = GPIO_INDEX(bank, gpio); | 	unsigned offset = GPIO_INDEX(bank, gpio); | ||||||
|  | @ -821,7 +812,7 @@ static void gpio_irq_shutdown(struct irq_data *d) | ||||||
| 
 | 
 | ||||||
| static void gpio_ack_irq(struct irq_data *d) | static void gpio_ack_irq(struct irq_data *d) | ||||||
| { | { | ||||||
| 	struct gpio_bank *bank = irq_data_get_irq_chip_data(d); | 	struct gpio_bank *bank = _irq_data_get_bank(d); | ||||||
| 	unsigned int gpio = irq_to_gpio(bank, d->hwirq); | 	unsigned int gpio = irq_to_gpio(bank, d->hwirq); | ||||||
| 
 | 
 | ||||||
| 	_clear_gpio_irqstatus(bank, gpio); | 	_clear_gpio_irqstatus(bank, gpio); | ||||||
|  | @ -829,7 +820,7 @@ static void gpio_ack_irq(struct irq_data *d) | ||||||
| 
 | 
 | ||||||
| static void gpio_mask_irq(struct irq_data *d) | static void gpio_mask_irq(struct irq_data *d) | ||||||
| { | { | ||||||
| 	struct gpio_bank *bank = irq_data_get_irq_chip_data(d); | 	struct gpio_bank *bank = _irq_data_get_bank(d); | ||||||
| 	unsigned int gpio = irq_to_gpio(bank, d->hwirq); | 	unsigned int gpio = irq_to_gpio(bank, d->hwirq); | ||||||
| 	unsigned long flags; | 	unsigned long flags; | ||||||
| 
 | 
 | ||||||
|  | @ -841,7 +832,7 @@ static void gpio_mask_irq(struct irq_data *d) | ||||||
| 
 | 
 | ||||||
| static void gpio_unmask_irq(struct irq_data *d) | static void gpio_unmask_irq(struct irq_data *d) | ||||||
| { | { | ||||||
| 	struct gpio_bank *bank = irq_data_get_irq_chip_data(d); | 	struct gpio_bank *bank = _irq_data_get_bank(d); | ||||||
| 	unsigned int gpio = irq_to_gpio(bank, d->hwirq); | 	unsigned int gpio = irq_to_gpio(bank, d->hwirq); | ||||||
| 	unsigned int irq_mask = GPIO_BIT(bank, gpio); | 	unsigned int irq_mask = GPIO_BIT(bank, gpio); | ||||||
| 	u32 trigger = irqd_get_trigger_type(d); | 	u32 trigger = irqd_get_trigger_type(d); | ||||||
|  | @ -1085,6 +1076,7 @@ static int omap_gpio_chip_init(struct gpio_bank *bank) | ||||||
| { | { | ||||||
| 	int j; | 	int j; | ||||||
| 	static int gpio; | 	static int gpio; | ||||||
|  | 	int irq_base = 0; | ||||||
| 	int ret; | 	int ret; | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
|  | @ -1098,7 +1090,6 @@ static int omap_gpio_chip_init(struct gpio_bank *bank) | ||||||
| 	bank->chip.direction_output = gpio_output; | 	bank->chip.direction_output = gpio_output; | ||||||
| 	bank->chip.set_debounce = gpio_debounce; | 	bank->chip.set_debounce = gpio_debounce; | ||||||
| 	bank->chip.set = gpio_set; | 	bank->chip.set = gpio_set; | ||||||
| 	bank->chip.to_irq = omap_gpio_to_irq; |  | ||||||
| 	if (bank->is_mpuio) { | 	if (bank->is_mpuio) { | ||||||
| 		bank->chip.label = "mpuio"; | 		bank->chip.label = "mpuio"; | ||||||
| 		if (bank->regs->wkup_en) | 		if (bank->regs->wkup_en) | ||||||
|  | @ -1113,24 +1104,46 @@ static int omap_gpio_chip_init(struct gpio_bank *bank) | ||||||
| 
 | 
 | ||||||
| 	ret = gpiochip_add(&bank->chip); | 	ret = gpiochip_add(&bank->chip); | ||||||
| 	if (ret) { | 	if (ret) { | ||||||
| 		dev_err(bank->dev, "Could not register gpio chip\n", ret); | 		dev_err(bank->dev, "Could not register gpio chip %d\n", ret); | ||||||
| 		return ret; | 		return ret; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | #ifdef CONFIG_ARCH_OMAP1 | ||||||
|  | 	/*
 | ||||||
|  | 	 * REVISIT: Once we have OMAP1 supporting SPARSE_IRQ, we can drop | ||||||
|  | 	 * irq_alloc_descs() since a base IRQ offset will no longer be needed. | ||||||
|  | 	 */ | ||||||
|  | 	irq_base = irq_alloc_descs(-1, 0, bank->width, 0); | ||||||
|  | 	if (irq_base < 0) { | ||||||
|  | 		dev_err(bank->dev, "Couldn't allocate IRQ numbers\n"); | ||||||
|  | 		return -ENODEV; | ||||||
|  | 	} | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | 	ret = gpiochip_irqchip_add(&bank->chip, &gpio_irq_chip, | ||||||
|  | 				   irq_base, gpio_irq_handler, | ||||||
|  | 				   IRQ_TYPE_NONE); | ||||||
|  | 
 | ||||||
|  | 	if (ret) { | ||||||
|  | 		dev_err(bank->dev, "Couldn't add irqchip to gpiochip %d\n", ret); | ||||||
|  | 		ret = gpiochip_remove(&bank->chip); | ||||||
|  | 		return -ENODEV; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	gpiochip_set_chained_irqchip(&bank->chip, &gpio_irq_chip, | ||||||
|  | 				     bank->irq, gpio_irq_handler); | ||||||
|  | 
 | ||||||
| 	for (j = 0; j < bank->width; j++) { | 	for (j = 0; j < bank->width; j++) { | ||||||
| 		int irq = irq_create_mapping(bank->domain, j); | 		int irq = irq_find_mapping(bank->chip.irqdomain, j); | ||||||
| 		irq_set_lockdep_class(irq, &gpio_lock_class); | 		irq_set_lockdep_class(irq, &gpio_lock_class); | ||||||
| 		irq_set_chip_data(irq, bank); |  | ||||||
| 		if (bank->is_mpuio) { | 		if (bank->is_mpuio) { | ||||||
| 			omap_mpuio_alloc_gc(bank, irq, bank->width); | 			omap_mpuio_alloc_gc(bank, irq, bank->width); | ||||||
| 		} else { | 			irq_set_chip_and_handler(irq, NULL, NULL); | ||||||
| 			irq_set_chip_and_handler(irq, &gpio_irq_chip, | 			set_irq_flags(irq, 0); | ||||||
| 						 handle_simple_irq); |  | ||||||
| 			set_irq_flags(irq, IRQF_VALID); |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	irq_set_chained_handler(bank->irq, gpio_irq_handler); | 
 | ||||||
| 	irq_set_handler_data(bank->irq, bank); | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static const struct of_device_id omap_gpio_match[]; | static const struct of_device_id omap_gpio_match[]; | ||||||
|  | @ -1143,7 +1156,6 @@ static int omap_gpio_probe(struct platform_device *pdev) | ||||||
| 	const struct omap_gpio_platform_data *pdata; | 	const struct omap_gpio_platform_data *pdata; | ||||||
| 	struct resource *res; | 	struct resource *res; | ||||||
| 	struct gpio_bank *bank; | 	struct gpio_bank *bank; | ||||||
| 	int irq_base = 0; |  | ||||||
| 	int ret; | 	int ret; | ||||||
| 
 | 
 | ||||||
| 	match = of_match_device(of_match_ptr(omap_gpio_match), dev); | 	match = of_match_device(of_match_ptr(omap_gpio_match), dev); | ||||||
|  | @ -1166,6 +1178,7 @@ static int omap_gpio_probe(struct platform_device *pdev) | ||||||
| 
 | 
 | ||||||
| 	bank->irq = res->start; | 	bank->irq = res->start; | ||||||
| 	bank->dev = dev; | 	bank->dev = dev; | ||||||
|  | 	bank->chip.dev = dev; | ||||||
| 	bank->dbck_flag = pdata->dbck_flag; | 	bank->dbck_flag = pdata->dbck_flag; | ||||||
| 	bank->stride = pdata->bank_stride; | 	bank->stride = pdata->bank_stride; | ||||||
| 	bank->width = pdata->bank_width; | 	bank->width = pdata->bank_width; | ||||||
|  | @ -1186,24 +1199,6 @@ static int omap_gpio_probe(struct platform_device *pdev) | ||||||
| 				pdata->get_context_loss_count; | 				pdata->get_context_loss_count; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| #ifdef CONFIG_ARCH_OMAP1 |  | ||||||
| 	/*
 |  | ||||||
| 	 * REVISIT: Once we have OMAP1 supporting SPARSE_IRQ, we can drop |  | ||||||
| 	 * irq_alloc_descs() since a base IRQ offset will no longer be needed. |  | ||||||
| 	 */ |  | ||||||
| 	irq_base = irq_alloc_descs(-1, 0, bank->width, 0); |  | ||||||
| 	if (irq_base < 0) { |  | ||||||
| 		dev_err(dev, "Couldn't allocate IRQ numbers\n"); |  | ||||||
| 		return -ENODEV; |  | ||||||
| 	} |  | ||||||
| #endif |  | ||||||
| 	bank->domain = irq_domain_add_simple(node, bank->width, irq_base, |  | ||||||
| 					     &irq_domain_simple_ops, NULL); |  | ||||||
| 	if (!bank->domain) { |  | ||||||
| 		dev_err(dev, "Couldn't register an IRQ domain\n"); |  | ||||||
| 		return -ENODEV; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if (bank->regs->set_dataout && bank->regs->clr_dataout) | 	if (bank->regs->set_dataout && bank->regs->clr_dataout) | ||||||
| 		bank->set_dataout = _set_gpio_dataout_reg; | 		bank->set_dataout = _set_gpio_dataout_reg; | ||||||
| 	else | 	else | ||||||
|  | @ -1215,7 +1210,7 @@ static int omap_gpio_probe(struct platform_device *pdev) | ||||||
| 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||||||
| 	bank->base = devm_ioremap_resource(dev, res); | 	bank->base = devm_ioremap_resource(dev, res); | ||||||
| 	if (IS_ERR(bank->base)) { | 	if (IS_ERR(bank->base)) { | ||||||
| 		irq_domain_remove(bank->domain); | 		irq_domain_remove(bank->chip.irqdomain); | ||||||
| 		return PTR_ERR(bank->base); | 		return PTR_ERR(bank->base); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Javier Martinez Canillas
						Javier Martinez Canillas