diff options
Diffstat (limited to 'drivers/gpio/gpio-tegra.c')
| -rw-r--r-- | drivers/gpio/gpio-tegra.c | 31 | 
1 files changed, 26 insertions, 5 deletions
diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 9a62672f1be..4e8fb8261a8 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -75,6 +75,7 @@ struct tegra_gpio_bank {  #endif  }; +static struct device *dev;  static struct irq_domain *irq_domain;  static void __iomem *regs;  static u32 tegra_gpio_bank_count; @@ -205,6 +206,7 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type)  	int lvl_type;  	int val;  	unsigned long flags; +	int ret;  	switch (type & IRQ_TYPE_SENSE_MASK) {  	case IRQ_TYPE_EDGE_RISING: @@ -231,6 +233,12 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type)  		return -EINVAL;  	} +	ret = gpio_lock_as_irq(&tegra_gpio_chip, gpio); +	if (ret) { +		dev_err(dev, "unable to lock Tegra GPIO %d as IRQ\n", gpio); +		return ret; +	} +  	spin_lock_irqsave(&bank->lvl_lock[port], flags);  	val = tegra_gpio_readl(GPIO_INT_LVL(gpio)); @@ -251,6 +259,13 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type)  	return 0;  } +static void tegra_gpio_irq_shutdown(struct irq_data *d) +{ +	int gpio = d->hwirq; + +	gpio_unlock_as_irq(&tegra_gpio_chip, gpio); +} +  static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)  {  	struct tegra_gpio_bank *bank; @@ -368,6 +383,7 @@ static struct irq_chip tegra_gpio_irq_chip = {  	.irq_mask	= tegra_gpio_irq_mask,  	.irq_unmask	= tegra_gpio_irq_unmask,  	.irq_set_type	= tegra_gpio_irq_set_type, +	.irq_shutdown	= tegra_gpio_irq_shutdown,  #ifdef CONFIG_PM_SLEEP  	.irq_set_wake	= tegra_gpio_irq_set_wake,  #endif @@ -392,7 +408,7 @@ static struct tegra_gpio_soc_config tegra30_gpio_config = {  	.upper_offset = 0x80,  }; -static struct of_device_id tegra_gpio_of_match[] = { +static const struct of_device_id tegra_gpio_of_match[] = {  	{ .compatible = "nvidia,tegra30-gpio", .data = &tegra30_gpio_config },  	{ .compatible = "nvidia,tegra20-gpio", .data = &tegra20_gpio_config },  	{ }, @@ -409,10 +425,13 @@ static int tegra_gpio_probe(struct platform_device *pdev)  	struct tegra_gpio_soc_config *config;  	struct resource *res;  	struct tegra_gpio_bank *bank; +	int ret;  	int gpio;  	int i;  	int j; +	dev = &pdev->dev; +  	match = of_match_device(tegra_gpio_of_match, &pdev->dev);  	if (!match) {  		dev_err(&pdev->dev, "Error: No device match found\n"); @@ -439,10 +458,8 @@ static int tegra_gpio_probe(struct platform_device *pdev)  	tegra_gpio_banks = devm_kzalloc(&pdev->dev,  			tegra_gpio_bank_count * sizeof(*tegra_gpio_banks),  			GFP_KERNEL); -	if (!tegra_gpio_banks) { -		dev_err(&pdev->dev, "Couldn't allocate bank structure\n"); +	if (!tegra_gpio_banks)  		return -ENODEV; -	}  	irq_domain = irq_domain_add_linear(pdev->dev.of_node,  					   tegra_gpio_chip.ngpio, @@ -476,7 +493,11 @@ static int tegra_gpio_probe(struct platform_device *pdev)  	tegra_gpio_chip.of_node = pdev->dev.of_node; -	gpiochip_add(&tegra_gpio_chip); +	ret = gpiochip_add(&tegra_gpio_chip); +	if (ret < 0) { +		irq_domain_remove(irq_domain); +		return ret; +	}  	for (gpio = 0; gpio < tegra_gpio_chip.ngpio; gpio++) {  		int irq = irq_create_mapping(irq_domain, gpio);  | 
