Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

gpio: hlwd: Add basic IRQ support

This patch implements level-triggered IRQs in the Hollywood GPIO driver.
Edge triggered interrupts are not supported in this GPIO controller, so
I moved their emulation into a separate patch.

Signed-off-by: Jonathan Neuschäfer <j.neuschaefer@gmx.net>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>

authored by

Jonathan Neuschäfer and committed by
Linus Walleij
588de43c 5c4fee63

+136 -1
+1
drivers/gpio/Kconfig
··· 258 258 tristate "Nintendo Wii (Hollywood) GPIO" 259 259 depends on OF_GPIO 260 260 select GPIO_GENERIC 261 + select GPIOLIB_IRQCHIP 261 262 help 262 263 Select this to support the GPIO controller of the Nintendo Wii. 263 264
+135 -1
drivers/gpio/gpio-hlwd.c
··· 48 48 49 49 struct hlwd_gpio { 50 50 struct gpio_chip gpioc; 51 + struct irq_chip irqc; 51 52 void __iomem *regs; 53 + int irq; 52 54 }; 55 + 56 + static void hlwd_gpio_irqhandler(struct irq_desc *desc) 57 + { 58 + struct hlwd_gpio *hlwd = 59 + gpiochip_get_data(irq_desc_get_handler_data(desc)); 60 + struct irq_chip *chip = irq_desc_get_chip(desc); 61 + unsigned long flags; 62 + unsigned long pending; 63 + int hwirq; 64 + 65 + spin_lock_irqsave(&hlwd->gpioc.bgpio_lock, flags); 66 + pending = ioread32be(hlwd->regs + HW_GPIOB_INTFLAG); 67 + pending &= ioread32be(hlwd->regs + HW_GPIOB_INTMASK); 68 + spin_unlock_irqrestore(&hlwd->gpioc.bgpio_lock, flags); 69 + 70 + chained_irq_enter(chip, desc); 71 + 72 + for_each_set_bit(hwirq, &pending, 32) { 73 + int irq = irq_find_mapping(hlwd->gpioc.irq.domain, hwirq); 74 + 75 + generic_handle_irq(irq); 76 + } 77 + 78 + chained_irq_exit(chip, desc); 79 + } 80 + 81 + static void hlwd_gpio_irq_ack(struct irq_data *data) 82 + { 83 + struct hlwd_gpio *hlwd = 84 + gpiochip_get_data(irq_data_get_irq_chip_data(data)); 85 + 86 + iowrite32be(BIT(data->hwirq), hlwd->regs + HW_GPIOB_INTFLAG); 87 + } 88 + 89 + static void hlwd_gpio_irq_mask(struct irq_data *data) 90 + { 91 + struct hlwd_gpio *hlwd = 92 + gpiochip_get_data(irq_data_get_irq_chip_data(data)); 93 + unsigned long flags; 94 + u32 mask; 95 + 96 + spin_lock_irqsave(&hlwd->gpioc.bgpio_lock, flags); 97 + mask = ioread32be(hlwd->regs + HW_GPIOB_INTMASK); 98 + mask &= ~BIT(data->hwirq); 99 + iowrite32be(mask, hlwd->regs + HW_GPIOB_INTMASK); 100 + spin_unlock_irqrestore(&hlwd->gpioc.bgpio_lock, flags); 101 + } 102 + 103 + static void hlwd_gpio_irq_unmask(struct irq_data *data) 104 + { 105 + struct hlwd_gpio *hlwd = 106 + gpiochip_get_data(irq_data_get_irq_chip_data(data)); 107 + unsigned long flags; 108 + u32 mask; 109 + 110 + spin_lock_irqsave(&hlwd->gpioc.bgpio_lock, flags); 111 + mask = ioread32be(hlwd->regs + HW_GPIOB_INTMASK); 112 + mask |= BIT(data->hwirq); 113 + iowrite32be(mask, hlwd->regs + HW_GPIOB_INTMASK); 114 + spin_unlock_irqrestore(&hlwd->gpioc.bgpio_lock, flags); 115 + } 116 + 117 + static void hlwd_gpio_irq_enable(struct irq_data *data) 118 + { 119 + hlwd_gpio_irq_ack(data); 120 + hlwd_gpio_irq_unmask(data); 121 + } 122 + 123 + static int hlwd_gpio_irq_set_type(struct irq_data *data, unsigned int flow_type) 124 + { 125 + struct hlwd_gpio *hlwd = 126 + gpiochip_get_data(irq_data_get_irq_chip_data(data)); 127 + unsigned long flags; 128 + u32 level; 129 + 130 + spin_lock_irqsave(&hlwd->gpioc.bgpio_lock, flags); 131 + 132 + switch (flow_type) { 133 + case IRQ_TYPE_LEVEL_HIGH: 134 + level = ioread32be(hlwd->regs + HW_GPIOB_INTLVL); 135 + level |= BIT(data->hwirq); 136 + iowrite32be(level, hlwd->regs + HW_GPIOB_INTLVL); 137 + break; 138 + case IRQ_TYPE_LEVEL_LOW: 139 + level = ioread32be(hlwd->regs + HW_GPIOB_INTLVL); 140 + level &= ~BIT(data->hwirq); 141 + iowrite32be(level, hlwd->regs + HW_GPIOB_INTLVL); 142 + break; 143 + default: 144 + spin_unlock_irqrestore(&hlwd->gpioc.bgpio_lock, flags); 145 + return -EINVAL; 146 + } 147 + 148 + spin_unlock_irqrestore(&hlwd->gpioc.bgpio_lock, flags); 149 + return 0; 150 + } 53 151 54 152 static int hlwd_gpio_probe(struct platform_device *pdev) 55 153 { ··· 190 92 ngpios = 32; 191 93 hlwd->gpioc.ngpio = ngpios; 192 94 193 - return devm_gpiochip_add_data(&pdev->dev, &hlwd->gpioc, hlwd); 95 + res = devm_gpiochip_add_data(&pdev->dev, &hlwd->gpioc, hlwd); 96 + if (res) 97 + return res; 98 + 99 + /* Mask and ack all interrupts */ 100 + iowrite32be(0, hlwd->regs + HW_GPIOB_INTMASK); 101 + iowrite32be(0xffffffff, hlwd->regs + HW_GPIOB_INTFLAG); 102 + 103 + /* 104 + * If this GPIO controller is not marked as an interrupt controller in 105 + * the DT, return. 106 + */ 107 + if (!of_property_read_bool(pdev->dev.of_node, "interrupt-controller")) 108 + return 0; 109 + 110 + hlwd->irq = platform_get_irq(pdev, 0); 111 + if (hlwd->irq < 0) { 112 + dev_info(&pdev->dev, "platform_get_irq returned %d\n", 113 + hlwd->irq); 114 + return hlwd->irq; 115 + } 116 + 117 + hlwd->irqc.name = dev_name(&pdev->dev); 118 + hlwd->irqc.irq_mask = hlwd_gpio_irq_mask; 119 + hlwd->irqc.irq_unmask = hlwd_gpio_irq_unmask; 120 + hlwd->irqc.irq_enable = hlwd_gpio_irq_enable; 121 + hlwd->irqc.irq_set_type = hlwd_gpio_irq_set_type; 122 + 123 + res = gpiochip_irqchip_add(&hlwd->gpioc, &hlwd->irqc, 0, 124 + handle_level_irq, IRQ_TYPE_NONE); 125 + if (res) 126 + return res; 127 + 128 + gpiochip_set_chained_irqchip(&hlwd->gpioc, &hlwd->irqc, 129 + hlwd->irq, hlwd_gpio_irqhandler); 130 + 131 + return 0; 194 132 } 195 133 196 134 static const struct of_device_id hlwd_gpio_match[] = {