X-Git-Url: http://git.linex4red.de/pub/spi-gpio-pp.git/blobdiff_plain/e539cfa0af8f19cb21fca37079e4805935814ba5..813458776ee097275c377f19853773b39dab193a:/gpio_test.c diff --git a/gpio_test.c b/gpio_test.c new file mode 100644 index 0000000..90d0892 --- /dev/null +++ b/gpio_test.c @@ -0,0 +1,174 @@ +/* + * gpio_test.c - GPIO test driver + * + * Copyright (C) 2008 Peter Henn + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * It just triggers a specified GPIO line setup the output + */ +#include +#include +#include +#include +#include + + +//***************************************************************************** +// MODULE PARAMETERS +//***************************************************************************** +#define DRVNAME "gpio_test" /* name of the driver */ +#define DRIVER_VERSION "0.1" /* helps identifing different versions of that driver */ +#define LABEL NULL + +static unsigned int gpi; +static unsigned int gpo; +static unsigned int val; +static unsigned int irq = -1; + +typedef struct { + int out_cansleep; + int in_cansleep; + int irq; + int cnt; +} gpio_t_struct; + +static gpio_t_struct gt; + +static irqreturn_t gpio_test_irq_handler(int irq, void *dev_id) +{ + + // todo use dev_id to get pointer to own driver structure data; + // container can be memory init with GPK_KERNEL + if (irq == gt.irq) { + gt.cnt++; + val = !val; + if (!gt.in_cansleep) { + pr_info("%s: GPIO #%d in value %d with counter %d\n", DRVNAME, gpi, gpio_get_value(gpi), gt.cnt); + } + if (!gt.out_cansleep) { + gpio_set_value(gpo, !val); + } + } + return IRQ_HANDLED; +} + +/* +** just set here the value +*/ +static int __init gpio_test_init(void) +{ + int err; + err = gpio_is_valid(gpo); + if (err<0) { + pr_err("%s: GPIO #%d for output is not usable\n", DRVNAME, gpo); + return err; + } + //ToDo: Test, how a text might be used as LABEL + err = gpio_request(gpo, LABEL); + if (err<0) { + pr_err("%s: GPIO #%d for output is can not be requested\n", DRVNAME, gpo); + return err; + } + gt.out_cansleep = gpio_cansleep(gpo); + pr_info("%s: GPIO #%d for output %s sleep\n", DRVNAME, gpo, ((gt.out_cansleep>0) ? "can" : "will not")); + err = gpio_direction_output(gpo, val); + if (err<0) { + pr_err("%s: GPIO #%d output direction is not possible\n", DRVNAME, gpo); + gpio_free(gpo); + return err; + } + + err = gpio_is_valid(gpi); + if (err<0) { + pr_err("%s: GPIO #%d for inout is not usable\n", DRVNAME, gpi); + gpio_free(gpo); + return err; + } + err = gpio_request(gpi, LABEL); + if (err<0) { + pr_err("%s: GPIO #%d for input is can not be requested\n", DRVNAME, gpi); + gpio_free(gpo); + return err; + } + gt.in_cansleep = gpio_cansleep(gpi); + pr_info("%s: GPIO #%d for input %s sleep\n", DRVNAME, gpi, ((gt.in_cansleep>0) ? "can" : "will not")); + gt.irq = gpio_to_irq(gpi); + if (gt.irq<0) { + pr_info("%s: GPIO #%d IRQ is not supported\n", DRVNAME, gpi); + gt.irq = irq; + if (gt.irq >= 0) { + pr_info("%s: we force interrupt to IRQ %d\n", DRVNAME, gt.irq); + } + } else { + pr_info("%s: GPIO #%d IRQ %d is supported\n", DRVNAME, gpi, gt.irq); + } + /* gpio_direction_output must be call from task context, we use insmod as task context here */ + err = gpio_direction_input(gpi); + if (err<0) { + pr_err("%s: GPIO #%d input direction is not possible\n", DRVNAME, gpi); + gpio_free(gpo); + gpio_free(gpi); + return err; + } + gt.cnt=0; + /* register irq handler */ + // ToDo: Test with other flag types: IRQF_SHARED, IRQF_TRIGGER_* + if (gt.irq >= 0) { + err = request_irq(gt.irq, gpio_test_irq_handler, IRQF_TRIGGER_NONE, "gpio_test_handler", NULL); + if (err<0) { + pr_err("%s: GPIO #%d IRQ %d can not be requested, got %d\n", DRVNAME, gpi, gt.irq, err); + gt.irq = -1; + } + } + return 0; +} + +device_initcall(gpio_test_init); + +/* +** just restore here the old value +*/ +static void __exit gpio_test_exit(void) +{ + if (gt.out_cansleep) { + gpio_set_value_cansleep(gpo, !val); + } else { + gpio_set_value(gpo, !val); + } + if (gt.irq >= 0) free_irq(gt.irq, NULL); + gpio_free(gpo); + gpio_free(gpi); +} +module_exit(gpio_test_exit); + +module_param(gpo, uint, S_IRUGO); +MODULE_PARM_DESC(gpo, "GPIO output address or number"); + +module_param(gpi, uint, S_IRUGO); +MODULE_PARM_DESC(gpi, "GPIO input address or number"); + +module_param(val, bool, S_IRUGO); +MODULE_PARM_DESC(val, "GPIO output value 0 or 1"); + +module_param(irq, uint, S_IRUGO); +MODULE_PARM_DESC(irq, "GPIO interrupt number"); + + +MODULE_AUTHOR("Option Wireless"); +MODULE_DESCRIPTION("GPIO output test"); +MODULE_LICENSE("GPL"); + +MODULE_INFO(Version, DRIVER_VERSION);