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

gpio: Add support for IDT 79RC3243x GPIO controller

IDT 79RC3243x SoCs integrated a gpio controller, which handles up
to 32 gpios. All gpios could be used as an interrupt source.

Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>

authored by

Thomas Bogendoerfer and committed by
Bartosz Golaszewski
4195926a 9b3c47f1

+219
+12
drivers/gpio/Kconfig
··· 782 782 Say Y here to support the main GPIO block on MStar/SigmaStar 783 783 ARMv7 based SoCs. 784 784 785 + config GPIO_IDT3243X 786 + tristate "IDT 79RC3243X GPIO support" 787 + depends on MIKROTIK_RB532 || COMPILE_TEST 788 + select GPIO_GENERIC 789 + select GPIOLIB_IRQCHIP 790 + help 791 + Select this option to enable GPIO driver for 792 + IDT 79RC3243X based devices like Mikrotik RB532. 793 + 794 + To compile this driver as a module, choose M here: the module will 795 + be called gpio-idt3243x. 796 + 785 797 endmenu 786 798 787 799 menu "Port-mapped I/O GPIO drivers"
+1
drivers/gpio/Makefile
··· 68 68 obj-$(CONFIG_GPIO_HLWD) += gpio-hlwd.o 69 69 obj-$(CONFIG_HTC_EGPIO) += gpio-htc-egpio.o 70 70 obj-$(CONFIG_GPIO_ICH) += gpio-ich.o 71 + obj-$(CONFIG_GPIO_IDT3243X) += gpio-idt3243x.o 71 72 obj-$(CONFIG_GPIO_IOP) += gpio-iop.o 72 73 obj-$(CONFIG_GPIO_IT87) += gpio-it87.o 73 74 obj-$(CONFIG_GPIO_IXP4XX) += gpio-ixp4xx.o
+206
drivers/gpio/gpio-idt3243x.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Driver for IDT/Renesas 79RC3243x Interrupt Controller */ 3 + 4 + #include <linux/bitops.h> 5 + #include <linux/gpio/driver.h> 6 + #include <linux/irq.h> 7 + #include <linux/module.h> 8 + #include <linux/mod_devicetable.h> 9 + #include <linux/platform_device.h> 10 + #include <linux/spinlock.h> 11 + 12 + #define IDT_PIC_IRQ_PEND 0x00 13 + #define IDT_PIC_IRQ_MASK 0x08 14 + 15 + #define IDT_GPIO_DIR 0x00 16 + #define IDT_GPIO_DATA 0x04 17 + #define IDT_GPIO_ILEVEL 0x08 18 + #define IDT_GPIO_ISTAT 0x0C 19 + 20 + struct idt_gpio_ctrl { 21 + struct gpio_chip gc; 22 + void __iomem *pic; 23 + void __iomem *gpio; 24 + u32 mask_cache; 25 + }; 26 + 27 + static void idt_gpio_dispatch(struct irq_desc *desc) 28 + { 29 + struct gpio_chip *gc = irq_desc_get_handler_data(desc); 30 + struct idt_gpio_ctrl *ctrl = gpiochip_get_data(gc); 31 + struct irq_chip *host_chip = irq_desc_get_chip(desc); 32 + unsigned int bit, virq; 33 + unsigned long pending; 34 + 35 + chained_irq_enter(host_chip, desc); 36 + 37 + pending = readl(ctrl->pic + IDT_PIC_IRQ_PEND); 38 + pending &= ~ctrl->mask_cache; 39 + for_each_set_bit(bit, &pending, gc->ngpio) { 40 + virq = irq_linear_revmap(gc->irq.domain, bit); 41 + if (virq) 42 + generic_handle_irq(virq); 43 + } 44 + 45 + chained_irq_exit(host_chip, desc); 46 + } 47 + 48 + static int idt_gpio_irq_set_type(struct irq_data *d, unsigned int flow_type) 49 + { 50 + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 51 + struct idt_gpio_ctrl *ctrl = gpiochip_get_data(gc); 52 + unsigned int sense = flow_type & IRQ_TYPE_SENSE_MASK; 53 + unsigned long flags; 54 + u32 ilevel; 55 + 56 + /* hardware only supports level triggered */ 57 + if (sense == IRQ_TYPE_NONE || (sense & IRQ_TYPE_EDGE_BOTH)) 58 + return -EINVAL; 59 + 60 + spin_lock_irqsave(&gc->bgpio_lock, flags); 61 + 62 + ilevel = readl(ctrl->gpio + IDT_GPIO_ILEVEL); 63 + if (sense & IRQ_TYPE_LEVEL_HIGH) 64 + ilevel |= BIT(d->hwirq); 65 + else if (sense & IRQ_TYPE_LEVEL_LOW) 66 + ilevel &= ~BIT(d->hwirq); 67 + 68 + writel(ilevel, ctrl->gpio + IDT_GPIO_ILEVEL); 69 + irq_set_handler_locked(d, handle_level_irq); 70 + 71 + spin_unlock_irqrestore(&gc->bgpio_lock, flags); 72 + return 0; 73 + } 74 + 75 + static void idt_gpio_ack(struct irq_data *d) 76 + { 77 + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 78 + struct idt_gpio_ctrl *ctrl = gpiochip_get_data(gc); 79 + 80 + writel(~BIT(d->hwirq), ctrl->gpio + IDT_GPIO_ISTAT); 81 + } 82 + 83 + static void idt_gpio_mask(struct irq_data *d) 84 + { 85 + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 86 + struct idt_gpio_ctrl *ctrl = gpiochip_get_data(gc); 87 + unsigned long flags; 88 + 89 + spin_lock_irqsave(&gc->bgpio_lock, flags); 90 + 91 + ctrl->mask_cache |= BIT(d->hwirq); 92 + writel(ctrl->mask_cache, ctrl->pic + IDT_PIC_IRQ_MASK); 93 + 94 + spin_unlock_irqrestore(&gc->bgpio_lock, flags); 95 + } 96 + 97 + static void idt_gpio_unmask(struct irq_data *d) 98 + { 99 + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 100 + struct idt_gpio_ctrl *ctrl = gpiochip_get_data(gc); 101 + unsigned long flags; 102 + 103 + spin_lock_irqsave(&gc->bgpio_lock, flags); 104 + 105 + ctrl->mask_cache &= ~BIT(d->hwirq); 106 + writel(ctrl->mask_cache, ctrl->pic + IDT_PIC_IRQ_MASK); 107 + 108 + spin_unlock_irqrestore(&gc->bgpio_lock, flags); 109 + } 110 + 111 + static int idt_gpio_irq_init_hw(struct gpio_chip *gc) 112 + { 113 + struct idt_gpio_ctrl *ctrl = gpiochip_get_data(gc); 114 + 115 + /* Mask interrupts. */ 116 + ctrl->mask_cache = 0xffffffff; 117 + writel(ctrl->mask_cache, ctrl->pic + IDT_PIC_IRQ_MASK); 118 + 119 + return 0; 120 + } 121 + 122 + static struct irq_chip idt_gpio_irqchip = { 123 + .name = "IDTGPIO", 124 + .irq_mask = idt_gpio_mask, 125 + .irq_ack = idt_gpio_ack, 126 + .irq_unmask = idt_gpio_unmask, 127 + .irq_set_type = idt_gpio_irq_set_type 128 + }; 129 + 130 + static int idt_gpio_probe(struct platform_device *pdev) 131 + { 132 + struct device *dev = &pdev->dev; 133 + struct gpio_irq_chip *girq; 134 + struct idt_gpio_ctrl *ctrl; 135 + unsigned int parent_irq; 136 + int ngpios; 137 + int ret; 138 + 139 + 140 + ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL); 141 + if (!ctrl) 142 + return -ENOMEM; 143 + 144 + ctrl->gpio = devm_platform_ioremap_resource_byname(pdev, "gpio"); 145 + if (!ctrl->gpio) 146 + return -ENOMEM; 147 + 148 + ctrl->gc.parent = dev; 149 + 150 + ret = bgpio_init(&ctrl->gc, &pdev->dev, 4, ctrl->gpio + IDT_GPIO_DATA, 151 + NULL, NULL, ctrl->gpio + IDT_GPIO_DIR, NULL, 0); 152 + if (ret) { 153 + dev_err(dev, "bgpio_init failed\n"); 154 + return ret; 155 + } 156 + 157 + ret = device_property_read_u32(dev, "ngpios", &ngpios); 158 + if (!ret) 159 + ctrl->gc.ngpio = ngpios; 160 + 161 + if (device_property_read_bool(dev, "interrupt-controller")) { 162 + ctrl->pic = devm_platform_ioremap_resource_byname(pdev, "pic"); 163 + if (!ctrl->pic) 164 + return -ENOMEM; 165 + 166 + parent_irq = platform_get_irq(pdev, 0); 167 + if (!parent_irq) 168 + return -EINVAL; 169 + 170 + girq = &ctrl->gc.irq; 171 + girq->chip = &idt_gpio_irqchip; 172 + girq->init_hw = idt_gpio_irq_init_hw; 173 + girq->parent_handler = idt_gpio_dispatch; 174 + girq->num_parents = 1; 175 + girq->parents = devm_kcalloc(dev, girq->num_parents, 176 + sizeof(*girq->parents), 177 + GFP_KERNEL); 178 + if (!girq->parents) 179 + return -ENOMEM; 180 + 181 + girq->parents[0] = parent_irq; 182 + girq->default_type = IRQ_TYPE_NONE; 183 + girq->handler = handle_bad_irq; 184 + } 185 + 186 + return devm_gpiochip_add_data(&pdev->dev, &ctrl->gc, ctrl); 187 + } 188 + 189 + static const struct of_device_id idt_gpio_of_match[] = { 190 + { .compatible = "idt,32434-gpio" }, 191 + { } 192 + }; 193 + MODULE_DEVICE_TABLE(of, idt_gpio_of_match); 194 + 195 + static struct platform_driver idt_gpio_driver = { 196 + .probe = idt_gpio_probe, 197 + .driver = { 198 + .name = "idt3243x-gpio", 199 + .of_match_table = idt_gpio_of_match, 200 + }, 201 + }; 202 + module_platform_driver(idt_gpio_driver); 203 + 204 + MODULE_DESCRIPTION("IDT 79RC3243x GPIO/PIC Driver"); 205 + MODULE_AUTHOR("Thomas Bogendoerfer <tsbogend@alpha.franken.de>"); 206 + MODULE_LICENSE("GPL");