11ccea77eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2c5abbba9STien Hock Loh /* 3c5abbba9STien Hock Loh * Copyright (C) 2013 Altera Corporation 4c5abbba9STien Hock Loh * Based on gpio-mpc8xxx.c 5c5abbba9STien Hock Loh */ 6c5abbba9STien Hock Loh 7c5abbba9STien Hock Loh #include <linux/io.h> 87b5409eeSPaul Gortmaker #include <linux/module.h> 940a1f9b2SLinus Walleij #include <linux/gpio/driver.h> 1040a1f9b2SLinus Walleij #include <linux/of_gpio.h> /* For of_mm_gpio_chip */ 11c5abbba9STien Hock Loh #include <linux/platform_device.h> 12c5abbba9STien Hock Loh 13c5abbba9STien Hock Loh #define ALTERA_GPIO_MAX_NGPIO 32 14c5abbba9STien Hock Loh #define ALTERA_GPIO_DATA 0x0 15c5abbba9STien Hock Loh #define ALTERA_GPIO_DIR 0x4 16c5abbba9STien Hock Loh #define ALTERA_GPIO_IRQ_MASK 0x8 17c5abbba9STien Hock Loh #define ALTERA_GPIO_EDGE_CAP 0xc 18c5abbba9STien Hock Loh 19c5abbba9STien Hock Loh /** 20c5abbba9STien Hock Loh * struct altera_gpio_chip 21c5abbba9STien Hock Loh * @mmchip : memory mapped chip structure. 22c5abbba9STien Hock Loh * @gpio_lock : synchronization lock so that new irq/set/get requests 239ce01efeSPhil Reid * will be blocked until the current one completes. 24c5abbba9STien Hock Loh * @interrupt_trigger : specifies the hardware configured IRQ trigger type 259ce01efeSPhil Reid * (rising, falling, both, high) 26c5abbba9STien Hock Loh * @mapped_irq : kernel mapped irq number. 27c5abbba9STien Hock Loh */ 28c5abbba9STien Hock Loh struct altera_gpio_chip { 29c5abbba9STien Hock Loh struct of_mm_gpio_chip mmchip; 3021d01c9cSJulia Cartwright raw_spinlock_t gpio_lock; 31c5abbba9STien Hock Loh int interrupt_trigger; 32c5abbba9STien Hock Loh int mapped_irq; 33*9d373acaSPhil Reid struct irq_chip irq_chip; 34c5abbba9STien Hock Loh }; 35c5abbba9STien Hock Loh 36c5abbba9STien Hock Loh static void altera_gpio_irq_unmask(struct irq_data *d) 37c5abbba9STien Hock Loh { 38c5abbba9STien Hock Loh struct altera_gpio_chip *altera_gc; 39c5abbba9STien Hock Loh struct of_mm_gpio_chip *mm_gc; 40c5abbba9STien Hock Loh unsigned long flags; 41c5abbba9STien Hock Loh u32 intmask; 42c5abbba9STien Hock Loh 43397d0773SLinus Walleij altera_gc = gpiochip_get_data(irq_data_get_irq_chip_data(d)); 44c5abbba9STien Hock Loh mm_gc = &altera_gc->mmchip; 45c5abbba9STien Hock Loh 4621d01c9cSJulia Cartwright raw_spin_lock_irqsave(&altera_gc->gpio_lock, flags); 47c5abbba9STien Hock Loh intmask = readl(mm_gc->regs + ALTERA_GPIO_IRQ_MASK); 48c5abbba9STien Hock Loh /* Set ALTERA_GPIO_IRQ_MASK bit to unmask */ 49c5abbba9STien Hock Loh intmask |= BIT(irqd_to_hwirq(d)); 50c5abbba9STien Hock Loh writel(intmask, mm_gc->regs + ALTERA_GPIO_IRQ_MASK); 5121d01c9cSJulia Cartwright raw_spin_unlock_irqrestore(&altera_gc->gpio_lock, flags); 52c5abbba9STien Hock Loh } 53c5abbba9STien Hock Loh 54c5abbba9STien Hock Loh static void altera_gpio_irq_mask(struct irq_data *d) 55c5abbba9STien Hock Loh { 56c5abbba9STien Hock Loh struct altera_gpio_chip *altera_gc; 57c5abbba9STien Hock Loh struct of_mm_gpio_chip *mm_gc; 58c5abbba9STien Hock Loh unsigned long flags; 59c5abbba9STien Hock Loh u32 intmask; 60c5abbba9STien Hock Loh 61397d0773SLinus Walleij altera_gc = gpiochip_get_data(irq_data_get_irq_chip_data(d)); 62c5abbba9STien Hock Loh mm_gc = &altera_gc->mmchip; 63c5abbba9STien Hock Loh 6421d01c9cSJulia Cartwright raw_spin_lock_irqsave(&altera_gc->gpio_lock, flags); 65c5abbba9STien Hock Loh intmask = readl(mm_gc->regs + ALTERA_GPIO_IRQ_MASK); 66c5abbba9STien Hock Loh /* Clear ALTERA_GPIO_IRQ_MASK bit to mask */ 67c5abbba9STien Hock Loh intmask &= ~BIT(irqd_to_hwirq(d)); 68c5abbba9STien Hock Loh writel(intmask, mm_gc->regs + ALTERA_GPIO_IRQ_MASK); 6921d01c9cSJulia Cartwright raw_spin_unlock_irqrestore(&altera_gc->gpio_lock, flags); 70c5abbba9STien Hock Loh } 71c5abbba9STien Hock Loh 72c5abbba9STien Hock Loh /** 73c5abbba9STien Hock Loh * This controller's IRQ type is synthesized in hardware, so this function 74c5abbba9STien Hock Loh * just checks if the requested set_type matches the synthesized IRQ type 75c5abbba9STien Hock Loh */ 76c5abbba9STien Hock Loh static int altera_gpio_irq_set_type(struct irq_data *d, 77c5abbba9STien Hock Loh unsigned int type) 78c5abbba9STien Hock Loh { 79c5abbba9STien Hock Loh struct altera_gpio_chip *altera_gc; 80c5abbba9STien Hock Loh 81397d0773SLinus Walleij altera_gc = gpiochip_get_data(irq_data_get_irq_chip_data(d)); 82c5abbba9STien Hock Loh 83f759921cSPhil Reid if (type == IRQ_TYPE_NONE) { 84f759921cSPhil Reid irq_set_handler_locked(d, handle_bad_irq); 85c5abbba9STien Hock Loh return 0; 86f759921cSPhil Reid } 87f759921cSPhil Reid if (type == altera_gc->interrupt_trigger) { 88f759921cSPhil Reid if (type == IRQ_TYPE_LEVEL_HIGH) 89f759921cSPhil Reid irq_set_handler_locked(d, handle_level_irq); 90f759921cSPhil Reid else 91f759921cSPhil Reid irq_set_handler_locked(d, handle_simple_irq); 92c5abbba9STien Hock Loh return 0; 93f759921cSPhil Reid } 94f759921cSPhil Reid irq_set_handler_locked(d, handle_bad_irq); 95c5abbba9STien Hock Loh return -EINVAL; 96c5abbba9STien Hock Loh } 97c5abbba9STien Hock Loh 9838e003f4SDaniel Lockyer static unsigned int altera_gpio_irq_startup(struct irq_data *d) 9938e003f4SDaniel Lockyer { 100c5abbba9STien Hock Loh altera_gpio_irq_unmask(d); 101c5abbba9STien Hock Loh 102c5abbba9STien Hock Loh return 0; 103c5abbba9STien Hock Loh } 104c5abbba9STien Hock Loh 105c5abbba9STien Hock Loh static int altera_gpio_get(struct gpio_chip *gc, unsigned offset) 106c5abbba9STien Hock Loh { 107c5abbba9STien Hock Loh struct of_mm_gpio_chip *mm_gc; 108c5abbba9STien Hock Loh 109c5abbba9STien Hock Loh mm_gc = to_of_mm_gpio_chip(gc); 110c5abbba9STien Hock Loh 111c5abbba9STien Hock Loh return !!(readl(mm_gc->regs + ALTERA_GPIO_DATA) & BIT(offset)); 112c5abbba9STien Hock Loh } 113c5abbba9STien Hock Loh 114c5abbba9STien Hock Loh static void altera_gpio_set(struct gpio_chip *gc, unsigned offset, int value) 115c5abbba9STien Hock Loh { 116c5abbba9STien Hock Loh struct of_mm_gpio_chip *mm_gc; 117c5abbba9STien Hock Loh struct altera_gpio_chip *chip; 118c5abbba9STien Hock Loh unsigned long flags; 119c5abbba9STien Hock Loh unsigned int data_reg; 120c5abbba9STien Hock Loh 121c5abbba9STien Hock Loh mm_gc = to_of_mm_gpio_chip(gc); 122397d0773SLinus Walleij chip = gpiochip_get_data(gc); 123c5abbba9STien Hock Loh 12421d01c9cSJulia Cartwright raw_spin_lock_irqsave(&chip->gpio_lock, flags); 125c5abbba9STien Hock Loh data_reg = readl(mm_gc->regs + ALTERA_GPIO_DATA); 126c5abbba9STien Hock Loh if (value) 127c5abbba9STien Hock Loh data_reg |= BIT(offset); 128c5abbba9STien Hock Loh else 129c5abbba9STien Hock Loh data_reg &= ~BIT(offset); 130c5abbba9STien Hock Loh writel(data_reg, mm_gc->regs + ALTERA_GPIO_DATA); 13121d01c9cSJulia Cartwright raw_spin_unlock_irqrestore(&chip->gpio_lock, flags); 132c5abbba9STien Hock Loh } 133c5abbba9STien Hock Loh 134c5abbba9STien Hock Loh static int altera_gpio_direction_input(struct gpio_chip *gc, unsigned offset) 135c5abbba9STien Hock Loh { 136c5abbba9STien Hock Loh struct of_mm_gpio_chip *mm_gc; 137c5abbba9STien Hock Loh struct altera_gpio_chip *chip; 138c5abbba9STien Hock Loh unsigned long flags; 139c5abbba9STien Hock Loh unsigned int gpio_ddr; 140c5abbba9STien Hock Loh 141c5abbba9STien Hock Loh mm_gc = to_of_mm_gpio_chip(gc); 142397d0773SLinus Walleij chip = gpiochip_get_data(gc); 143c5abbba9STien Hock Loh 14421d01c9cSJulia Cartwright raw_spin_lock_irqsave(&chip->gpio_lock, flags); 145c5abbba9STien Hock Loh /* Set pin as input, assumes software controlled IP */ 146c5abbba9STien Hock Loh gpio_ddr = readl(mm_gc->regs + ALTERA_GPIO_DIR); 147c5abbba9STien Hock Loh gpio_ddr &= ~BIT(offset); 148c5abbba9STien Hock Loh writel(gpio_ddr, mm_gc->regs + ALTERA_GPIO_DIR); 14921d01c9cSJulia Cartwright raw_spin_unlock_irqrestore(&chip->gpio_lock, flags); 150c5abbba9STien Hock Loh 151c5abbba9STien Hock Loh return 0; 152c5abbba9STien Hock Loh } 153c5abbba9STien Hock Loh 154c5abbba9STien Hock Loh static int altera_gpio_direction_output(struct gpio_chip *gc, 155c5abbba9STien Hock Loh unsigned offset, int value) 156c5abbba9STien Hock Loh { 157c5abbba9STien Hock Loh struct of_mm_gpio_chip *mm_gc; 158c5abbba9STien Hock Loh struct altera_gpio_chip *chip; 159c5abbba9STien Hock Loh unsigned long flags; 160c5abbba9STien Hock Loh unsigned int data_reg, gpio_ddr; 161c5abbba9STien Hock Loh 162c5abbba9STien Hock Loh mm_gc = to_of_mm_gpio_chip(gc); 163397d0773SLinus Walleij chip = gpiochip_get_data(gc); 164c5abbba9STien Hock Loh 16521d01c9cSJulia Cartwright raw_spin_lock_irqsave(&chip->gpio_lock, flags); 166c5abbba9STien Hock Loh /* Sets the GPIO value */ 167c5abbba9STien Hock Loh data_reg = readl(mm_gc->regs + ALTERA_GPIO_DATA); 168c5abbba9STien Hock Loh if (value) 169c5abbba9STien Hock Loh data_reg |= BIT(offset); 170c5abbba9STien Hock Loh else 171c5abbba9STien Hock Loh data_reg &= ~BIT(offset); 172c5abbba9STien Hock Loh writel(data_reg, mm_gc->regs + ALTERA_GPIO_DATA); 173c5abbba9STien Hock Loh 174c5abbba9STien Hock Loh /* Set pin as output, assumes software controlled IP */ 175c5abbba9STien Hock Loh gpio_ddr = readl(mm_gc->regs + ALTERA_GPIO_DIR); 176c5abbba9STien Hock Loh gpio_ddr |= BIT(offset); 177c5abbba9STien Hock Loh writel(gpio_ddr, mm_gc->regs + ALTERA_GPIO_DIR); 17821d01c9cSJulia Cartwright raw_spin_unlock_irqrestore(&chip->gpio_lock, flags); 179c5abbba9STien Hock Loh 180c5abbba9STien Hock Loh return 0; 181c5abbba9STien Hock Loh } 182c5abbba9STien Hock Loh 183bd0b9ac4SThomas Gleixner static void altera_gpio_irq_edge_handler(struct irq_desc *desc) 184c5abbba9STien Hock Loh { 185c5abbba9STien Hock Loh struct altera_gpio_chip *altera_gc; 186c5abbba9STien Hock Loh struct irq_chip *chip; 187c5abbba9STien Hock Loh struct of_mm_gpio_chip *mm_gc; 188c5abbba9STien Hock Loh struct irq_domain *irqdomain; 189c5abbba9STien Hock Loh unsigned long status; 190c5abbba9STien Hock Loh int i; 191c5abbba9STien Hock Loh 192397d0773SLinus Walleij altera_gc = gpiochip_get_data(irq_desc_get_handler_data(desc)); 193c5abbba9STien Hock Loh chip = irq_desc_get_chip(desc); 194c5abbba9STien Hock Loh mm_gc = &altera_gc->mmchip; 195f0fbe7bcSThierry Reding irqdomain = altera_gc->mmchip.gc.irq.domain; 196c5abbba9STien Hock Loh 197c5abbba9STien Hock Loh chained_irq_enter(chip, desc); 198c5abbba9STien Hock Loh 199c5abbba9STien Hock Loh while ((status = 200c5abbba9STien Hock Loh (readl(mm_gc->regs + ALTERA_GPIO_EDGE_CAP) & 201c5abbba9STien Hock Loh readl(mm_gc->regs + ALTERA_GPIO_IRQ_MASK)))) { 202c5abbba9STien Hock Loh writel(status, mm_gc->regs + ALTERA_GPIO_EDGE_CAP); 203c5abbba9STien Hock Loh for_each_set_bit(i, &status, mm_gc->gc.ngpio) { 204c5abbba9STien Hock Loh generic_handle_irq(irq_find_mapping(irqdomain, i)); 205c5abbba9STien Hock Loh } 206c5abbba9STien Hock Loh } 207c5abbba9STien Hock Loh 208c5abbba9STien Hock Loh chained_irq_exit(chip, desc); 209c5abbba9STien Hock Loh } 210c5abbba9STien Hock Loh 211bd0b9ac4SThomas Gleixner static void altera_gpio_irq_leveL_high_handler(struct irq_desc *desc) 212c5abbba9STien Hock Loh { 213c5abbba9STien Hock Loh struct altera_gpio_chip *altera_gc; 214c5abbba9STien Hock Loh struct irq_chip *chip; 215c5abbba9STien Hock Loh struct of_mm_gpio_chip *mm_gc; 216c5abbba9STien Hock Loh struct irq_domain *irqdomain; 217c5abbba9STien Hock Loh unsigned long status; 218c5abbba9STien Hock Loh int i; 219c5abbba9STien Hock Loh 220397d0773SLinus Walleij altera_gc = gpiochip_get_data(irq_desc_get_handler_data(desc)); 221c5abbba9STien Hock Loh chip = irq_desc_get_chip(desc); 222c5abbba9STien Hock Loh mm_gc = &altera_gc->mmchip; 223f0fbe7bcSThierry Reding irqdomain = altera_gc->mmchip.gc.irq.domain; 224c5abbba9STien Hock Loh 225c5abbba9STien Hock Loh chained_irq_enter(chip, desc); 226c5abbba9STien Hock Loh 227c5abbba9STien Hock Loh status = readl(mm_gc->regs + ALTERA_GPIO_DATA); 228c5abbba9STien Hock Loh status &= readl(mm_gc->regs + ALTERA_GPIO_IRQ_MASK); 229c5abbba9STien Hock Loh 230c5abbba9STien Hock Loh for_each_set_bit(i, &status, mm_gc->gc.ngpio) { 231c5abbba9STien Hock Loh generic_handle_irq(irq_find_mapping(irqdomain, i)); 232c5abbba9STien Hock Loh } 233c5abbba9STien Hock Loh chained_irq_exit(chip, desc); 234c5abbba9STien Hock Loh } 235c5abbba9STien Hock Loh 236c4b40493Skbuild test robot static int altera_gpio_probe(struct platform_device *pdev) 237c5abbba9STien Hock Loh { 238c5abbba9STien Hock Loh struct device_node *node = pdev->dev.of_node; 239c5abbba9STien Hock Loh int reg, ret; 240c5abbba9STien Hock Loh struct altera_gpio_chip *altera_gc; 241c5abbba9STien Hock Loh 242c5abbba9STien Hock Loh altera_gc = devm_kzalloc(&pdev->dev, sizeof(*altera_gc), GFP_KERNEL); 243c5abbba9STien Hock Loh if (!altera_gc) 244c5abbba9STien Hock Loh return -ENOMEM; 245c5abbba9STien Hock Loh 24621d01c9cSJulia Cartwright raw_spin_lock_init(&altera_gc->gpio_lock); 247c5abbba9STien Hock Loh 248c5abbba9STien Hock Loh if (of_property_read_u32(node, "altr,ngpio", ®)) 249c5abbba9STien Hock Loh /* By default assume maximum ngpio */ 250c5abbba9STien Hock Loh altera_gc->mmchip.gc.ngpio = ALTERA_GPIO_MAX_NGPIO; 251c5abbba9STien Hock Loh else 252c5abbba9STien Hock Loh altera_gc->mmchip.gc.ngpio = reg; 253c5abbba9STien Hock Loh 254c5abbba9STien Hock Loh if (altera_gc->mmchip.gc.ngpio > ALTERA_GPIO_MAX_NGPIO) { 255c5abbba9STien Hock Loh dev_warn(&pdev->dev, 256c5abbba9STien Hock Loh "ngpio is greater than %d, defaulting to %d\n", 257c5abbba9STien Hock Loh ALTERA_GPIO_MAX_NGPIO, ALTERA_GPIO_MAX_NGPIO); 258c5abbba9STien Hock Loh altera_gc->mmchip.gc.ngpio = ALTERA_GPIO_MAX_NGPIO; 259c5abbba9STien Hock Loh } 260c5abbba9STien Hock Loh 261c5abbba9STien Hock Loh altera_gc->mmchip.gc.direction_input = altera_gpio_direction_input; 262c5abbba9STien Hock Loh altera_gc->mmchip.gc.direction_output = altera_gpio_direction_output; 263c5abbba9STien Hock Loh altera_gc->mmchip.gc.get = altera_gpio_get; 264c5abbba9STien Hock Loh altera_gc->mmchip.gc.set = altera_gpio_set; 265c5abbba9STien Hock Loh altera_gc->mmchip.gc.owner = THIS_MODULE; 26658383c78SLinus Walleij altera_gc->mmchip.gc.parent = &pdev->dev; 267c5abbba9STien Hock Loh 268397d0773SLinus Walleij ret = of_mm_gpiochip_add_data(node, &altera_gc->mmchip, altera_gc); 269c5abbba9STien Hock Loh if (ret) { 270c5abbba9STien Hock Loh dev_err(&pdev->dev, "Failed adding memory mapped gpiochip\n"); 271c5abbba9STien Hock Loh return ret; 272c5abbba9STien Hock Loh } 273c5abbba9STien Hock Loh 274c5abbba9STien Hock Loh platform_set_drvdata(pdev, altera_gc); 275c5abbba9STien Hock Loh 276c5abbba9STien Hock Loh altera_gc->mapped_irq = platform_get_irq(pdev, 0); 277c5abbba9STien Hock Loh 278c5abbba9STien Hock Loh if (altera_gc->mapped_irq < 0) 279c5abbba9STien Hock Loh goto skip_irq; 280c5abbba9STien Hock Loh 281c5abbba9STien Hock Loh if (of_property_read_u32(node, "altr,interrupt-type", ®)) { 282c5abbba9STien Hock Loh ret = -EINVAL; 283c5abbba9STien Hock Loh dev_err(&pdev->dev, 284c5abbba9STien Hock Loh "altr,interrupt-type value not set in device tree\n"); 285c5abbba9STien Hock Loh goto teardown; 286c5abbba9STien Hock Loh } 287c5abbba9STien Hock Loh altera_gc->interrupt_trigger = reg; 288c5abbba9STien Hock Loh 289*9d373acaSPhil Reid altera_gc->irq_chip.name = "altera-gpio"; 290*9d373acaSPhil Reid altera_gc->irq_chip.irq_mask = altera_gpio_irq_mask; 291*9d373acaSPhil Reid altera_gc->irq_chip.irq_unmask = altera_gpio_irq_unmask; 292*9d373acaSPhil Reid altera_gc->irq_chip.irq_set_type = altera_gpio_irq_set_type; 293*9d373acaSPhil Reid altera_gc->irq_chip.irq_startup = altera_gpio_irq_startup; 294*9d373acaSPhil Reid altera_gc->irq_chip.irq_shutdown = altera_gpio_irq_mask; 295*9d373acaSPhil Reid 296*9d373acaSPhil Reid ret = gpiochip_irqchip_add(&altera_gc->mmchip.gc, &altera_gc->irq_chip, 297*9d373acaSPhil Reid 0, handle_bad_irq, IRQ_TYPE_NONE); 298c5abbba9STien Hock Loh 299c5abbba9STien Hock Loh if (ret) { 30073c13c83SPhil Reid dev_err(&pdev->dev, "could not add irqchip\n"); 30173c13c83SPhil Reid goto teardown; 302c5abbba9STien Hock Loh } 303c5abbba9STien Hock Loh 304c5abbba9STien Hock Loh gpiochip_set_chained_irqchip(&altera_gc->mmchip.gc, 305*9d373acaSPhil Reid &altera_gc->irq_chip, 306c5abbba9STien Hock Loh altera_gc->mapped_irq, 307c5abbba9STien Hock Loh altera_gc->interrupt_trigger == IRQ_TYPE_LEVEL_HIGH ? 308c5abbba9STien Hock Loh altera_gpio_irq_leveL_high_handler : 309c5abbba9STien Hock Loh altera_gpio_irq_edge_handler); 310c5abbba9STien Hock Loh 311c5abbba9STien Hock Loh skip_irq: 312c5abbba9STien Hock Loh return 0; 313c5abbba9STien Hock Loh teardown: 31473c13c83SPhil Reid of_mm_gpiochip_remove(&altera_gc->mmchip); 3157eb6ce2fSRob Herring pr_err("%pOF: registration failed with status %d\n", 3167eb6ce2fSRob Herring node, ret); 317c5abbba9STien Hock Loh 318c5abbba9STien Hock Loh return ret; 319c5abbba9STien Hock Loh } 320c5abbba9STien Hock Loh 321c5abbba9STien Hock Loh static int altera_gpio_remove(struct platform_device *pdev) 322c5abbba9STien Hock Loh { 323c5abbba9STien Hock Loh struct altera_gpio_chip *altera_gc = platform_get_drvdata(pdev); 324c5abbba9STien Hock Loh 32541ec66c9SMasahiro Yamada of_mm_gpiochip_remove(&altera_gc->mmchip); 326c5abbba9STien Hock Loh 3271c8b5d68SMasahiro Yamada return 0; 328c5abbba9STien Hock Loh } 329c5abbba9STien Hock Loh 330c5abbba9STien Hock Loh static const struct of_device_id altera_gpio_of_match[] = { 331c5abbba9STien Hock Loh { .compatible = "altr,pio-1.0", }, 332c5abbba9STien Hock Loh {}, 333c5abbba9STien Hock Loh }; 334c5abbba9STien Hock Loh MODULE_DEVICE_TABLE(of, altera_gpio_of_match); 335c5abbba9STien Hock Loh 336c5abbba9STien Hock Loh static struct platform_driver altera_gpio_driver = { 337c5abbba9STien Hock Loh .driver = { 338c5abbba9STien Hock Loh .name = "altera_gpio", 339c5abbba9STien Hock Loh .of_match_table = of_match_ptr(altera_gpio_of_match), 340c5abbba9STien Hock Loh }, 341c5abbba9STien Hock Loh .probe = altera_gpio_probe, 342c5abbba9STien Hock Loh .remove = altera_gpio_remove, 343c5abbba9STien Hock Loh }; 344c5abbba9STien Hock Loh 345c5abbba9STien Hock Loh static int __init altera_gpio_init(void) 346c5abbba9STien Hock Loh { 347c5abbba9STien Hock Loh return platform_driver_register(&altera_gpio_driver); 348c5abbba9STien Hock Loh } 349c5abbba9STien Hock Loh subsys_initcall(altera_gpio_init); 350c5abbba9STien Hock Loh 351c5abbba9STien Hock Loh static void __exit altera_gpio_exit(void) 352c5abbba9STien Hock Loh { 353c5abbba9STien Hock Loh platform_driver_unregister(&altera_gpio_driver); 354c5abbba9STien Hock Loh } 355c5abbba9STien Hock Loh module_exit(altera_gpio_exit); 356c5abbba9STien Hock Loh 357c5abbba9STien Hock Loh MODULE_AUTHOR("Tien Hock Loh <thloh@altera.com>"); 358c5abbba9STien Hock Loh MODULE_DESCRIPTION("Altera GPIO driver"); 359c5abbba9STien Hock Loh MODULE_LICENSE("GPL"); 360