1c5abbba9STien Hock Loh /* 2c5abbba9STien Hock Loh * Copyright (C) 2013 Altera Corporation 3c5abbba9STien Hock Loh * Based on gpio-mpc8xxx.c 4c5abbba9STien Hock Loh * 5c5abbba9STien Hock Loh * This program is free software; you can redistribute it and/or modify 6c5abbba9STien Hock Loh * it under the terms of the GNU General Public License as published by 7c5abbba9STien Hock Loh * the Free Software Foundation; either version 2 of the License, or 8c5abbba9STien Hock Loh * (at your option) any later version. 9c5abbba9STien Hock Loh * 10c5abbba9STien Hock Loh * This program is distributed in the hope that it will be useful, 11c5abbba9STien Hock Loh * but WITHOUT ANY WARRANTY; without even the implied warranty of 12c5abbba9STien Hock Loh * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13c5abbba9STien Hock Loh * GNU General Public License for more details. 14c5abbba9STien Hock Loh * 15c5abbba9STien Hock Loh * You should have received a copy of the GNU General Public License 16c5abbba9STien Hock Loh * along with this program. If not, see <http://www.gnu.org/licenses/>. 17c5abbba9STien Hock Loh */ 18c5abbba9STien Hock Loh 19c5abbba9STien Hock Loh #include <linux/io.h> 207b5409eeSPaul Gortmaker #include <linux/module.h> 21c5abbba9STien Hock Loh #include <linux/of_gpio.h> 22c5abbba9STien Hock Loh #include <linux/platform_device.h> 23c5abbba9STien Hock Loh 24c5abbba9STien Hock Loh #define ALTERA_GPIO_MAX_NGPIO 32 25c5abbba9STien Hock Loh #define ALTERA_GPIO_DATA 0x0 26c5abbba9STien Hock Loh #define ALTERA_GPIO_DIR 0x4 27c5abbba9STien Hock Loh #define ALTERA_GPIO_IRQ_MASK 0x8 28c5abbba9STien Hock Loh #define ALTERA_GPIO_EDGE_CAP 0xc 29c5abbba9STien Hock Loh 30c5abbba9STien Hock Loh /** 31c5abbba9STien Hock Loh * struct altera_gpio_chip 32c5abbba9STien Hock Loh * @mmchip : memory mapped chip structure. 33c5abbba9STien Hock Loh * @gpio_lock : synchronization lock so that new irq/set/get requests 34c5abbba9STien Hock Loh will be blocked until the current one completes. 35c5abbba9STien Hock Loh * @interrupt_trigger : specifies the hardware configured IRQ trigger type 36c5abbba9STien Hock Loh (rising, falling, both, high) 37c5abbba9STien Hock Loh * @mapped_irq : kernel mapped irq number. 38c5abbba9STien Hock Loh */ 39c5abbba9STien Hock Loh struct altera_gpio_chip { 40c5abbba9STien Hock Loh struct of_mm_gpio_chip mmchip; 4121d01c9cSJulia Cartwright raw_spinlock_t gpio_lock; 42c5abbba9STien Hock Loh int interrupt_trigger; 43c5abbba9STien Hock Loh int mapped_irq; 44c5abbba9STien Hock Loh }; 45c5abbba9STien Hock Loh 46c5abbba9STien Hock Loh static void altera_gpio_irq_unmask(struct irq_data *d) 47c5abbba9STien Hock Loh { 48c5abbba9STien Hock Loh struct altera_gpio_chip *altera_gc; 49c5abbba9STien Hock Loh struct of_mm_gpio_chip *mm_gc; 50c5abbba9STien Hock Loh unsigned long flags; 51c5abbba9STien Hock Loh u32 intmask; 52c5abbba9STien Hock Loh 53397d0773SLinus Walleij altera_gc = gpiochip_get_data(irq_data_get_irq_chip_data(d)); 54c5abbba9STien Hock Loh mm_gc = &altera_gc->mmchip; 55c5abbba9STien Hock Loh 5621d01c9cSJulia Cartwright raw_spin_lock_irqsave(&altera_gc->gpio_lock, flags); 57c5abbba9STien Hock Loh intmask = readl(mm_gc->regs + ALTERA_GPIO_IRQ_MASK); 58c5abbba9STien Hock Loh /* Set ALTERA_GPIO_IRQ_MASK bit to unmask */ 59c5abbba9STien Hock Loh intmask |= BIT(irqd_to_hwirq(d)); 60c5abbba9STien Hock Loh writel(intmask, mm_gc->regs + ALTERA_GPIO_IRQ_MASK); 6121d01c9cSJulia Cartwright raw_spin_unlock_irqrestore(&altera_gc->gpio_lock, flags); 62c5abbba9STien Hock Loh } 63c5abbba9STien Hock Loh 64c5abbba9STien Hock Loh static void altera_gpio_irq_mask(struct irq_data *d) 65c5abbba9STien Hock Loh { 66c5abbba9STien Hock Loh struct altera_gpio_chip *altera_gc; 67c5abbba9STien Hock Loh struct of_mm_gpio_chip *mm_gc; 68c5abbba9STien Hock Loh unsigned long flags; 69c5abbba9STien Hock Loh u32 intmask; 70c5abbba9STien Hock Loh 71397d0773SLinus Walleij altera_gc = gpiochip_get_data(irq_data_get_irq_chip_data(d)); 72c5abbba9STien Hock Loh mm_gc = &altera_gc->mmchip; 73c5abbba9STien Hock Loh 7421d01c9cSJulia Cartwright raw_spin_lock_irqsave(&altera_gc->gpio_lock, flags); 75c5abbba9STien Hock Loh intmask = readl(mm_gc->regs + ALTERA_GPIO_IRQ_MASK); 76c5abbba9STien Hock Loh /* Clear ALTERA_GPIO_IRQ_MASK bit to mask */ 77c5abbba9STien Hock Loh intmask &= ~BIT(irqd_to_hwirq(d)); 78c5abbba9STien Hock Loh writel(intmask, mm_gc->regs + ALTERA_GPIO_IRQ_MASK); 7921d01c9cSJulia Cartwright raw_spin_unlock_irqrestore(&altera_gc->gpio_lock, flags); 80c5abbba9STien Hock Loh } 81c5abbba9STien Hock Loh 82c5abbba9STien Hock Loh /** 83c5abbba9STien Hock Loh * This controller's IRQ type is synthesized in hardware, so this function 84c5abbba9STien Hock Loh * just checks if the requested set_type matches the synthesized IRQ type 85c5abbba9STien Hock Loh */ 86c5abbba9STien Hock Loh static int altera_gpio_irq_set_type(struct irq_data *d, 87c5abbba9STien Hock Loh unsigned int type) 88c5abbba9STien Hock Loh { 89c5abbba9STien Hock Loh struct altera_gpio_chip *altera_gc; 90c5abbba9STien Hock Loh 91397d0773SLinus Walleij altera_gc = gpiochip_get_data(irq_data_get_irq_chip_data(d)); 92c5abbba9STien Hock Loh 93f759921cSPhil Reid if (type == IRQ_TYPE_NONE) { 94f759921cSPhil Reid irq_set_handler_locked(d, handle_bad_irq); 95c5abbba9STien Hock Loh return 0; 96f759921cSPhil Reid } 97f759921cSPhil Reid if (type == altera_gc->interrupt_trigger) { 98f759921cSPhil Reid if (type == IRQ_TYPE_LEVEL_HIGH) 99f759921cSPhil Reid irq_set_handler_locked(d, handle_level_irq); 100f759921cSPhil Reid else 101f759921cSPhil Reid irq_set_handler_locked(d, handle_simple_irq); 102c5abbba9STien Hock Loh return 0; 103f759921cSPhil Reid } 104f759921cSPhil Reid irq_set_handler_locked(d, handle_bad_irq); 105c5abbba9STien Hock Loh return -EINVAL; 106c5abbba9STien Hock Loh } 107c5abbba9STien Hock Loh 10838e003f4SDaniel Lockyer static unsigned int altera_gpio_irq_startup(struct irq_data *d) 10938e003f4SDaniel Lockyer { 110c5abbba9STien Hock Loh altera_gpio_irq_unmask(d); 111c5abbba9STien Hock Loh 112c5abbba9STien Hock Loh return 0; 113c5abbba9STien Hock Loh } 114c5abbba9STien Hock Loh 115c5abbba9STien Hock Loh static struct irq_chip altera_irq_chip = { 116c5abbba9STien Hock Loh .name = "altera-gpio", 117c5abbba9STien Hock Loh .irq_mask = altera_gpio_irq_mask, 118c5abbba9STien Hock Loh .irq_unmask = altera_gpio_irq_unmask, 119c5abbba9STien Hock Loh .irq_set_type = altera_gpio_irq_set_type, 120c5abbba9STien Hock Loh .irq_startup = altera_gpio_irq_startup, 121c5abbba9STien Hock Loh .irq_shutdown = altera_gpio_irq_mask, 122c5abbba9STien Hock Loh }; 123c5abbba9STien Hock Loh 124c5abbba9STien Hock Loh static int altera_gpio_get(struct gpio_chip *gc, unsigned offset) 125c5abbba9STien Hock Loh { 126c5abbba9STien Hock Loh struct of_mm_gpio_chip *mm_gc; 127c5abbba9STien Hock Loh 128c5abbba9STien Hock Loh mm_gc = to_of_mm_gpio_chip(gc); 129c5abbba9STien Hock Loh 130c5abbba9STien Hock Loh return !!(readl(mm_gc->regs + ALTERA_GPIO_DATA) & BIT(offset)); 131c5abbba9STien Hock Loh } 132c5abbba9STien Hock Loh 133c5abbba9STien Hock Loh static void altera_gpio_set(struct gpio_chip *gc, unsigned offset, int value) 134c5abbba9STien Hock Loh { 135c5abbba9STien Hock Loh struct of_mm_gpio_chip *mm_gc; 136c5abbba9STien Hock Loh struct altera_gpio_chip *chip; 137c5abbba9STien Hock Loh unsigned long flags; 138c5abbba9STien Hock Loh unsigned int data_reg; 139c5abbba9STien Hock Loh 140c5abbba9STien Hock Loh mm_gc = to_of_mm_gpio_chip(gc); 141397d0773SLinus Walleij chip = gpiochip_get_data(gc); 142c5abbba9STien Hock Loh 14321d01c9cSJulia Cartwright raw_spin_lock_irqsave(&chip->gpio_lock, flags); 144c5abbba9STien Hock Loh data_reg = readl(mm_gc->regs + ALTERA_GPIO_DATA); 145c5abbba9STien Hock Loh if (value) 146c5abbba9STien Hock Loh data_reg |= BIT(offset); 147c5abbba9STien Hock Loh else 148c5abbba9STien Hock Loh data_reg &= ~BIT(offset); 149c5abbba9STien Hock Loh writel(data_reg, mm_gc->regs + ALTERA_GPIO_DATA); 15021d01c9cSJulia Cartwright raw_spin_unlock_irqrestore(&chip->gpio_lock, flags); 151c5abbba9STien Hock Loh } 152c5abbba9STien Hock Loh 153c5abbba9STien Hock Loh static int altera_gpio_direction_input(struct gpio_chip *gc, unsigned offset) 154c5abbba9STien Hock Loh { 155c5abbba9STien Hock Loh struct of_mm_gpio_chip *mm_gc; 156c5abbba9STien Hock Loh struct altera_gpio_chip *chip; 157c5abbba9STien Hock Loh unsigned long flags; 158c5abbba9STien Hock Loh unsigned int gpio_ddr; 159c5abbba9STien Hock Loh 160c5abbba9STien Hock Loh mm_gc = to_of_mm_gpio_chip(gc); 161397d0773SLinus Walleij chip = gpiochip_get_data(gc); 162c5abbba9STien Hock Loh 16321d01c9cSJulia Cartwright raw_spin_lock_irqsave(&chip->gpio_lock, flags); 164c5abbba9STien Hock Loh /* Set pin as input, assumes software controlled IP */ 165c5abbba9STien Hock Loh gpio_ddr = readl(mm_gc->regs + ALTERA_GPIO_DIR); 166c5abbba9STien Hock Loh gpio_ddr &= ~BIT(offset); 167c5abbba9STien Hock Loh writel(gpio_ddr, mm_gc->regs + ALTERA_GPIO_DIR); 16821d01c9cSJulia Cartwright raw_spin_unlock_irqrestore(&chip->gpio_lock, flags); 169c5abbba9STien Hock Loh 170c5abbba9STien Hock Loh return 0; 171c5abbba9STien Hock Loh } 172c5abbba9STien Hock Loh 173c5abbba9STien Hock Loh static int altera_gpio_direction_output(struct gpio_chip *gc, 174c5abbba9STien Hock Loh unsigned offset, int value) 175c5abbba9STien Hock Loh { 176c5abbba9STien Hock Loh struct of_mm_gpio_chip *mm_gc; 177c5abbba9STien Hock Loh struct altera_gpio_chip *chip; 178c5abbba9STien Hock Loh unsigned long flags; 179c5abbba9STien Hock Loh unsigned int data_reg, gpio_ddr; 180c5abbba9STien Hock Loh 181c5abbba9STien Hock Loh mm_gc = to_of_mm_gpio_chip(gc); 182397d0773SLinus Walleij chip = gpiochip_get_data(gc); 183c5abbba9STien Hock Loh 18421d01c9cSJulia Cartwright raw_spin_lock_irqsave(&chip->gpio_lock, flags); 185c5abbba9STien Hock Loh /* Sets the GPIO value */ 186c5abbba9STien Hock Loh data_reg = readl(mm_gc->regs + ALTERA_GPIO_DATA); 187c5abbba9STien Hock Loh if (value) 188c5abbba9STien Hock Loh data_reg |= BIT(offset); 189c5abbba9STien Hock Loh else 190c5abbba9STien Hock Loh data_reg &= ~BIT(offset); 191c5abbba9STien Hock Loh writel(data_reg, mm_gc->regs + ALTERA_GPIO_DATA); 192c5abbba9STien Hock Loh 193c5abbba9STien Hock Loh /* Set pin as output, assumes software controlled IP */ 194c5abbba9STien Hock Loh gpio_ddr = readl(mm_gc->regs + ALTERA_GPIO_DIR); 195c5abbba9STien Hock Loh gpio_ddr |= BIT(offset); 196c5abbba9STien Hock Loh writel(gpio_ddr, mm_gc->regs + ALTERA_GPIO_DIR); 19721d01c9cSJulia Cartwright raw_spin_unlock_irqrestore(&chip->gpio_lock, flags); 198c5abbba9STien Hock Loh 199c5abbba9STien Hock Loh return 0; 200c5abbba9STien Hock Loh } 201c5abbba9STien Hock Loh 202bd0b9ac4SThomas Gleixner static void altera_gpio_irq_edge_handler(struct irq_desc *desc) 203c5abbba9STien Hock Loh { 204c5abbba9STien Hock Loh struct altera_gpio_chip *altera_gc; 205c5abbba9STien Hock Loh struct irq_chip *chip; 206c5abbba9STien Hock Loh struct of_mm_gpio_chip *mm_gc; 207c5abbba9STien Hock Loh struct irq_domain *irqdomain; 208c5abbba9STien Hock Loh unsigned long status; 209c5abbba9STien Hock Loh int i; 210c5abbba9STien Hock Loh 211397d0773SLinus Walleij altera_gc = gpiochip_get_data(irq_desc_get_handler_data(desc)); 212c5abbba9STien Hock Loh chip = irq_desc_get_chip(desc); 213c5abbba9STien Hock Loh mm_gc = &altera_gc->mmchip; 214*f0fbe7bcSThierry Reding irqdomain = altera_gc->mmchip.gc.irq.domain; 215c5abbba9STien Hock Loh 216c5abbba9STien Hock Loh chained_irq_enter(chip, desc); 217c5abbba9STien Hock Loh 218c5abbba9STien Hock Loh while ((status = 219c5abbba9STien Hock Loh (readl(mm_gc->regs + ALTERA_GPIO_EDGE_CAP) & 220c5abbba9STien Hock Loh readl(mm_gc->regs + ALTERA_GPIO_IRQ_MASK)))) { 221c5abbba9STien Hock Loh writel(status, mm_gc->regs + ALTERA_GPIO_EDGE_CAP); 222c5abbba9STien Hock Loh for_each_set_bit(i, &status, mm_gc->gc.ngpio) { 223c5abbba9STien Hock Loh generic_handle_irq(irq_find_mapping(irqdomain, i)); 224c5abbba9STien Hock Loh } 225c5abbba9STien Hock Loh } 226c5abbba9STien Hock Loh 227c5abbba9STien Hock Loh chained_irq_exit(chip, desc); 228c5abbba9STien Hock Loh } 229c5abbba9STien Hock Loh 230bd0b9ac4SThomas Gleixner static void altera_gpio_irq_leveL_high_handler(struct irq_desc *desc) 231c5abbba9STien Hock Loh { 232c5abbba9STien Hock Loh struct altera_gpio_chip *altera_gc; 233c5abbba9STien Hock Loh struct irq_chip *chip; 234c5abbba9STien Hock Loh struct of_mm_gpio_chip *mm_gc; 235c5abbba9STien Hock Loh struct irq_domain *irqdomain; 236c5abbba9STien Hock Loh unsigned long status; 237c5abbba9STien Hock Loh int i; 238c5abbba9STien Hock Loh 239397d0773SLinus Walleij altera_gc = gpiochip_get_data(irq_desc_get_handler_data(desc)); 240c5abbba9STien Hock Loh chip = irq_desc_get_chip(desc); 241c5abbba9STien Hock Loh mm_gc = &altera_gc->mmchip; 242*f0fbe7bcSThierry Reding irqdomain = altera_gc->mmchip.gc.irq.domain; 243c5abbba9STien Hock Loh 244c5abbba9STien Hock Loh chained_irq_enter(chip, desc); 245c5abbba9STien Hock Loh 246c5abbba9STien Hock Loh status = readl(mm_gc->regs + ALTERA_GPIO_DATA); 247c5abbba9STien Hock Loh status &= readl(mm_gc->regs + ALTERA_GPIO_IRQ_MASK); 248c5abbba9STien Hock Loh 249c5abbba9STien Hock Loh for_each_set_bit(i, &status, mm_gc->gc.ngpio) { 250c5abbba9STien Hock Loh generic_handle_irq(irq_find_mapping(irqdomain, i)); 251c5abbba9STien Hock Loh } 252c5abbba9STien Hock Loh chained_irq_exit(chip, desc); 253c5abbba9STien Hock Loh } 254c5abbba9STien Hock Loh 255c4b40493Skbuild test robot static int altera_gpio_probe(struct platform_device *pdev) 256c5abbba9STien Hock Loh { 257c5abbba9STien Hock Loh struct device_node *node = pdev->dev.of_node; 258c5abbba9STien Hock Loh int reg, ret; 259c5abbba9STien Hock Loh struct altera_gpio_chip *altera_gc; 260c5abbba9STien Hock Loh 261c5abbba9STien Hock Loh altera_gc = devm_kzalloc(&pdev->dev, sizeof(*altera_gc), GFP_KERNEL); 262c5abbba9STien Hock Loh if (!altera_gc) 263c5abbba9STien Hock Loh return -ENOMEM; 264c5abbba9STien Hock Loh 26521d01c9cSJulia Cartwright raw_spin_lock_init(&altera_gc->gpio_lock); 266c5abbba9STien Hock Loh 267c5abbba9STien Hock Loh if (of_property_read_u32(node, "altr,ngpio", ®)) 268c5abbba9STien Hock Loh /* By default assume maximum ngpio */ 269c5abbba9STien Hock Loh altera_gc->mmchip.gc.ngpio = ALTERA_GPIO_MAX_NGPIO; 270c5abbba9STien Hock Loh else 271c5abbba9STien Hock Loh altera_gc->mmchip.gc.ngpio = reg; 272c5abbba9STien Hock Loh 273c5abbba9STien Hock Loh if (altera_gc->mmchip.gc.ngpio > ALTERA_GPIO_MAX_NGPIO) { 274c5abbba9STien Hock Loh dev_warn(&pdev->dev, 275c5abbba9STien Hock Loh "ngpio is greater than %d, defaulting to %d\n", 276c5abbba9STien Hock Loh ALTERA_GPIO_MAX_NGPIO, ALTERA_GPIO_MAX_NGPIO); 277c5abbba9STien Hock Loh altera_gc->mmchip.gc.ngpio = ALTERA_GPIO_MAX_NGPIO; 278c5abbba9STien Hock Loh } 279c5abbba9STien Hock Loh 280c5abbba9STien Hock Loh altera_gc->mmchip.gc.direction_input = altera_gpio_direction_input; 281c5abbba9STien Hock Loh altera_gc->mmchip.gc.direction_output = altera_gpio_direction_output; 282c5abbba9STien Hock Loh altera_gc->mmchip.gc.get = altera_gpio_get; 283c5abbba9STien Hock Loh altera_gc->mmchip.gc.set = altera_gpio_set; 284c5abbba9STien Hock Loh altera_gc->mmchip.gc.owner = THIS_MODULE; 28558383c78SLinus Walleij altera_gc->mmchip.gc.parent = &pdev->dev; 286c5abbba9STien Hock Loh 287397d0773SLinus Walleij ret = of_mm_gpiochip_add_data(node, &altera_gc->mmchip, altera_gc); 288c5abbba9STien Hock Loh if (ret) { 289c5abbba9STien Hock Loh dev_err(&pdev->dev, "Failed adding memory mapped gpiochip\n"); 290c5abbba9STien Hock Loh return ret; 291c5abbba9STien Hock Loh } 292c5abbba9STien Hock Loh 293c5abbba9STien Hock Loh platform_set_drvdata(pdev, altera_gc); 294c5abbba9STien Hock Loh 295c5abbba9STien Hock Loh altera_gc->mapped_irq = platform_get_irq(pdev, 0); 296c5abbba9STien Hock Loh 297c5abbba9STien Hock Loh if (altera_gc->mapped_irq < 0) 298c5abbba9STien Hock Loh goto skip_irq; 299c5abbba9STien Hock Loh 300c5abbba9STien Hock Loh if (of_property_read_u32(node, "altr,interrupt-type", ®)) { 301c5abbba9STien Hock Loh ret = -EINVAL; 302c5abbba9STien Hock Loh dev_err(&pdev->dev, 303c5abbba9STien Hock Loh "altr,interrupt-type value not set in device tree\n"); 304c5abbba9STien Hock Loh goto teardown; 305c5abbba9STien Hock Loh } 306c5abbba9STien Hock Loh altera_gc->interrupt_trigger = reg; 307c5abbba9STien Hock Loh 308c5abbba9STien Hock Loh ret = gpiochip_irqchip_add(&altera_gc->mmchip.gc, &altera_irq_chip, 0, 309f759921cSPhil Reid handle_bad_irq, IRQ_TYPE_NONE); 310c5abbba9STien Hock Loh 311c5abbba9STien Hock Loh if (ret) { 31273c13c83SPhil Reid dev_err(&pdev->dev, "could not add irqchip\n"); 31373c13c83SPhil Reid goto teardown; 314c5abbba9STien Hock Loh } 315c5abbba9STien Hock Loh 316c5abbba9STien Hock Loh gpiochip_set_chained_irqchip(&altera_gc->mmchip.gc, 317c5abbba9STien Hock Loh &altera_irq_chip, 318c5abbba9STien Hock Loh altera_gc->mapped_irq, 319c5abbba9STien Hock Loh altera_gc->interrupt_trigger == IRQ_TYPE_LEVEL_HIGH ? 320c5abbba9STien Hock Loh altera_gpio_irq_leveL_high_handler : 321c5abbba9STien Hock Loh altera_gpio_irq_edge_handler); 322c5abbba9STien Hock Loh 323c5abbba9STien Hock Loh skip_irq: 324c5abbba9STien Hock Loh return 0; 325c5abbba9STien Hock Loh teardown: 32673c13c83SPhil Reid of_mm_gpiochip_remove(&altera_gc->mmchip); 3277eb6ce2fSRob Herring pr_err("%pOF: registration failed with status %d\n", 3287eb6ce2fSRob Herring node, ret); 329c5abbba9STien Hock Loh 330c5abbba9STien Hock Loh return ret; 331c5abbba9STien Hock Loh } 332c5abbba9STien Hock Loh 333c5abbba9STien Hock Loh static int altera_gpio_remove(struct platform_device *pdev) 334c5abbba9STien Hock Loh { 335c5abbba9STien Hock Loh struct altera_gpio_chip *altera_gc = platform_get_drvdata(pdev); 336c5abbba9STien Hock Loh 33741ec66c9SMasahiro Yamada of_mm_gpiochip_remove(&altera_gc->mmchip); 338c5abbba9STien Hock Loh 3391c8b5d68SMasahiro Yamada return 0; 340c5abbba9STien Hock Loh } 341c5abbba9STien Hock Loh 342c5abbba9STien Hock Loh static const struct of_device_id altera_gpio_of_match[] = { 343c5abbba9STien Hock Loh { .compatible = "altr,pio-1.0", }, 344c5abbba9STien Hock Loh {}, 345c5abbba9STien Hock Loh }; 346c5abbba9STien Hock Loh MODULE_DEVICE_TABLE(of, altera_gpio_of_match); 347c5abbba9STien Hock Loh 348c5abbba9STien Hock Loh static struct platform_driver altera_gpio_driver = { 349c5abbba9STien Hock Loh .driver = { 350c5abbba9STien Hock Loh .name = "altera_gpio", 351c5abbba9STien Hock Loh .of_match_table = of_match_ptr(altera_gpio_of_match), 352c5abbba9STien Hock Loh }, 353c5abbba9STien Hock Loh .probe = altera_gpio_probe, 354c5abbba9STien Hock Loh .remove = altera_gpio_remove, 355c5abbba9STien Hock Loh }; 356c5abbba9STien Hock Loh 357c5abbba9STien Hock Loh static int __init altera_gpio_init(void) 358c5abbba9STien Hock Loh { 359c5abbba9STien Hock Loh return platform_driver_register(&altera_gpio_driver); 360c5abbba9STien Hock Loh } 361c5abbba9STien Hock Loh subsys_initcall(altera_gpio_init); 362c5abbba9STien Hock Loh 363c5abbba9STien Hock Loh static void __exit altera_gpio_exit(void) 364c5abbba9STien Hock Loh { 365c5abbba9STien Hock Loh platform_driver_unregister(&altera_gpio_driver); 366c5abbba9STien Hock Loh } 367c5abbba9STien Hock Loh module_exit(altera_gpio_exit); 368c5abbba9STien Hock Loh 369c5abbba9STien Hock Loh MODULE_AUTHOR("Tien Hock Loh <thloh@altera.com>"); 370c5abbba9STien Hock Loh MODULE_DESCRIPTION("Altera GPIO driver"); 371c5abbba9STien Hock Loh MODULE_LICENSE("GPL"); 372