2 * gpio_test.c - GPIO test driver
4 * Copyright (C) 2008 Peter Henn
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 * It just triggers a specified GPIO line setup the output
22 #include <linux/kernel.h>
23 #include <linux/init.h>
24 #include <linux/device.h>
25 #include <linux/interrupt.h>
26 #include <linux/workqueue.h>
27 #include <linux/gpio.h>
30 //*****************************************************************************
32 //*****************************************************************************
33 #define DRVNAME "gpio_test" /* name of the driver */
34 #define DRIVER_VERSION "0.3" /* helps identifing different versions of that driver */
39 static unsigned int val
= 0;
47 struct tasklet_struct work_tasklet
;
50 static struct gpio_test
*gt
;
53 static void gpio_tasklet(unsigned long data
)
55 struct gpio_test
*g
= (struct gpio_test
*)data
;
56 pr_info("%s: Tasklet triggered: %d\n", DRVNAME
, g
->cnt
);
59 static irqreturn_t
gpio_test_irq_handler(int irq
, void *dev_id
)
61 struct gpio_test
*g
= (struct gpio_test
*)dev_id
;
62 // todo use dev_id to get pointer to own driver structure data;
63 // container can be memory init with GPK_KERNEL
66 tasklet_hi_schedule(&g
->work_tasklet
);
69 if (!g
->in_cansleep
) {
70 pr_info("%s: GPIO #%d in value %d with counter %d\n", DRVNAME
, gpi
, gpio_get_value(gpi
), g
->cnt
);
72 if ((gpo
>= 0) && !g
->out_cansleep
) {
73 gpio_set_value(gpo
, !val
);
83 ** just set here the value
85 static int __init
gpio_test_init(void)
88 gt
= kzalloc(sizeof(*gt
), GFP_KERNEL
);
92 /* ******* GPIO INPUT ******* */
94 pr_err("%s: GPI input required\n", DRVNAME
);
98 err
= gpio_is_valid(gpi
);
100 pr_err("%s: GPIO #%d for inout is not usable\n", DRVNAME
, gpi
);
104 err
= gpio_request(gpi
, LABEL
);
106 pr_err("%s: GPIO #%d for input is can not be requested\n", DRVNAME
, gpi
);
110 gt
->in_cansleep
= gpio_cansleep(gpi
);
111 pr_info("%s: GPIO #%d for input %s sleep\n", DRVNAME
, gpi
, ((gt
->in_cansleep
>0) ?
"can" : "will not"));
112 tasklet_init(>
->work_tasklet
,
113 (void (*)(unsigned long))gpio_tasklet
,
116 /* ******* GPIO INTERRUPT ******* */
117 gt
->irq
= gpio_to_irq(gpi
);
119 pr_info("%s: GPIO #%d IRQ is not supported\n", DRVNAME
, gpi
);
122 pr_info("%s: we force interrupt to IRQ %d\n", DRVNAME
, gt
->irq
);
125 pr_info("%s: GPIO #%d IRQ %d is supported\n", DRVNAME
, gpi
, gt
->irq
);
127 /* gpio_direction_input must be call from task context, we use insmod as task context here */
128 err
= gpio_direction_input(gpi
);
130 pr_err("%s: GPIO #%d input direction is not possible\n", DRVNAME
, gpi
);
131 tasklet_kill(>
->work_tasklet
);
136 /* register irq handler */
138 // ToDo: Test with other flag types: IRQF_SHARED, IRQF_TRIGGER_*
140 err
= request_irq(gt
->irq
, gpio_test_irq_handler
, IRQF_TRIGGER_NONE
, "gpio_test_handler", (void *)gt
);
142 pr_err("%s: GPIO #%d IRQ %d can not be requested, got %d\n", DRVNAME
, gpi
, gt
->irq
, err
);
148 /* ******* GPIO OUTPUT ******* */
150 err
= gpio_is_valid(gpo
);
152 pr_err("%s: GPIO #%d for output is not usable\n", DRVNAME
, gpo
);
153 if (gt
->irq
>= 0) free_irq(gt
->irq
, (void *)gt
);
154 tasklet_kill(>
->work_tasklet
);
159 err
= gpio_request(gpo
, LABEL
);
161 pr_err("%s: GPIO #%d for output is can not be requested\n", DRVNAME
, gpo
);
162 if (gt
->irq
>= 0) free_irq(gt
->irq
, (void *)gt
);
163 tasklet_kill(>
->work_tasklet
);
168 gt
->out_cansleep
= gpio_cansleep(gpo
);
169 pr_info("%s: GPIO #%d for output %s sleep\n", DRVNAME
, gpo
, ((gt
->out_cansleep
>0) ?
"can" : "will not"));
170 err
= gpio_direction_output(gpo
, val
);
172 pr_err("%s: GPIO #%d output direction is not possible\n", DRVNAME
, gpo
);
173 if (gt
->irq
>= 0) free_irq(gt
->irq
, (void *)gt
);
174 tasklet_kill(>
->work_tasklet
);
184 device_initcall(gpio_test_init
);
187 ** just restore here the old value
189 static void __exit
gpio_test_exit(void)
191 if (gt
->irq
>= 0) free_irq(gt
->irq
, (void *)gt
);
192 tasklet_kill(>
->work_tasklet
);
195 if (gt
->out_cansleep
) {
196 gpio_set_value_cansleep(gpo
, !val
);
198 gpio_set_value(gpo
, !val
);
204 module_exit(gpio_test_exit
);
206 module_param(gpo
, uint
, S_IRUGO
);
207 MODULE_PARM_DESC(gpo
, "GPIO output address or number");
209 module_param(gpi
, uint
, S_IRUGO
);
210 MODULE_PARM_DESC(gpi
, "GPIO input address or number");
212 module_param(val
, bool, S_IRUGO
);
213 MODULE_PARM_DESC(val
, "GPIO output value 0 or 1");
215 module_param(irq
, uint
, S_IRUGO
);
216 MODULE_PARM_DESC(irq
, "GPIO interrupt number");
219 MODULE_AUTHOR("Option Wireless");
220 MODULE_DESCRIPTION("GPIO output test");
221 MODULE_LICENSE("GPL");
223 MODULE_INFO(Version
, DRIVER_VERSION
);