1/* 2 * Copyright (C) 2012 CERN (www.cern.ch) 3 * Author: Alessandro Rubini <rubini@gnudd.com> 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * The software is provided "as is"; the copyright holders disclaim 10 * all warranties and liabilities, to the extent permitted by 11 * applicable law. 12 */ 13 14/* A trivial fmc driver that can load a gateware file and reports interrupts */ 15#include <linux/module.h> 16#include <linux/init.h> 17#include <linux/interrupt.h> 18#include <linux/gpio.h> 19#include <linux/fmc.h> 20 21static struct fmc_driver t_drv; /* initialized later */ 22 23static irqreturn_t t_handler(int irq, void *dev_id) 24{ 25 struct fmc_device *fmc = dev_id; 26 27 fmc->op->irq_ack(fmc); 28 dev_info(&fmc->dev, "received irq %i\n", irq); 29 return IRQ_HANDLED; 30} 31 32static struct fmc_gpio t_gpio[] = { 33 { 34 .gpio = FMC_GPIO_IRQ(0), 35 .mode = GPIOF_DIR_IN, 36 .irqmode = IRQF_TRIGGER_RISING, 37 }, { 38 .gpio = FMC_GPIO_IRQ(1), 39 .mode = GPIOF_DIR_IN, 40 .irqmode = IRQF_TRIGGER_RISING, 41 } 42}; 43 44static int t_probe(struct fmc_device *fmc) 45{ 46 int ret; 47 int index = 0; 48 49 if (fmc->op->validate) 50 index = fmc->op->validate(fmc, &t_drv); 51 if (index < 0) 52 return -EINVAL; /* not our device: invalid */ 53 54 ret = fmc->op->irq_request(fmc, t_handler, "fmc-trivial", IRQF_SHARED); 55 if (ret < 0) 56 return ret; 57 /* ignore error code of call below, we really don't care */ 58 fmc->op->gpio_config(fmc, t_gpio, ARRAY_SIZE(t_gpio)); 59 60 /* Reprogram, if asked to. ESRCH == no filename specified */ 61 ret = -ESRCH; 62 if (fmc->op->reprogram) 63 ret = fmc->op->reprogram(fmc, &t_drv, ""); 64 if (ret == -ESRCH) 65 ret = 0; 66 if (ret < 0) 67 fmc->op->irq_free(fmc); 68 69 /* FIXME: reprogram LM32 too */ 70 return ret; 71} 72 73static int t_remove(struct fmc_device *fmc) 74{ 75 fmc->op->irq_free(fmc); 76 return 0; 77} 78 79static struct fmc_driver t_drv = { 80 .version = FMC_VERSION, 81 .driver.name = KBUILD_MODNAME, 82 .probe = t_probe, 83 .remove = t_remove, 84 /* no table, as the current match just matches everything */ 85}; 86 87 /* We accept the generic parameters */ 88FMC_PARAM_BUSID(t_drv); 89FMC_PARAM_GATEWARE(t_drv); 90 91static int t_init(void) 92{ 93 int ret; 94 95 ret = fmc_driver_register(&t_drv); 96 return ret; 97} 98 99static void t_exit(void) 100{ 101 fmc_driver_unregister(&t_drv); 102} 103 104module_init(t_init); 105module_exit(t_exit); 106 107MODULE_LICENSE("Dual BSD/GPL"); 108