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