90d0892b7a13a166da616d956661337646596e62
[pub/spi-gpio-pp.git] / gpio_test.c
1 /*
2 * gpio_test.c - GPIO test driver
3 *
4 * Copyright (C) 2008 Peter Henn
5 *
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.
10 *
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.
15 *
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.
19 *
20 * It just triggers a specified GPIO line setup the output
21 */
22 #include <linux/kernel.h>
23 #include <linux/init.h>
24 #include <linux/device.h>
25 #include <linux/interrupt.h>
26 #include <linux/gpio.h>
27
28
29 //*****************************************************************************
30 // MODULE PARAMETERS
31 //*****************************************************************************
32 #define DRVNAME "gpio_test" /* name of the driver */
33 #define DRIVER_VERSION "0.1" /* helps identifing different versions of that driver */
34 #define LABEL NULL
35
36 static unsigned int gpi;
37 static unsigned int gpo;
38 static unsigned int val;
39 static unsigned int irq = -1;
40
41 typedef struct {
42 int out_cansleep;
43 int in_cansleep;
44 int irq;
45 int cnt;
46 } gpio_t_struct;
47
48 static gpio_t_struct gt;
49
50 static irqreturn_t gpio_test_irq_handler(int irq, void *dev_id)
51 {
52
53 // todo use dev_id to get pointer to own driver structure data;
54 // container can be memory init with GPK_KERNEL
55 if (irq == gt.irq) {
56 gt.cnt++;
57 val = !val;
58 if (!gt.in_cansleep) {
59 pr_info("%s: GPIO #%d in value %d with counter %d\n", DRVNAME, gpi, gpio_get_value(gpi), gt.cnt);
60 }
61 if (!gt.out_cansleep) {
62 gpio_set_value(gpo, !val);
63 }
64 }
65 return IRQ_HANDLED;
66 }
67
68 /*
69 ** just set here the value
70 */
71 static int __init gpio_test_init(void)
72 {
73 int err;
74 err = gpio_is_valid(gpo);
75 if (err<0) {
76 pr_err("%s: GPIO #%d for output is not usable\n", DRVNAME, gpo);
77 return err;
78 }
79 //ToDo: Test, how a text might be used as LABEL
80 err = gpio_request(gpo, LABEL);
81 if (err<0) {
82 pr_err("%s: GPIO #%d for output is can not be requested\n", DRVNAME, gpo);
83 return err;
84 }
85 gt.out_cansleep = gpio_cansleep(gpo);
86 pr_info("%s: GPIO #%d for output %s sleep\n", DRVNAME, gpo, ((gt.out_cansleep>0) ? "can" : "will not"));
87 err = gpio_direction_output(gpo, val);
88 if (err<0) {
89 pr_err("%s: GPIO #%d output direction is not possible\n", DRVNAME, gpo);
90 gpio_free(gpo);
91 return err;
92 }
93
94 err = gpio_is_valid(gpi);
95 if (err<0) {
96 pr_err("%s: GPIO #%d for inout is not usable\n", DRVNAME, gpi);
97 gpio_free(gpo);
98 return err;
99 }
100 err = gpio_request(gpi, LABEL);
101 if (err<0) {
102 pr_err("%s: GPIO #%d for input is can not be requested\n", DRVNAME, gpi);
103 gpio_free(gpo);
104 return err;
105 }
106 gt.in_cansleep = gpio_cansleep(gpi);
107 pr_info("%s: GPIO #%d for input %s sleep\n", DRVNAME, gpi, ((gt.in_cansleep>0) ? "can" : "will not"));
108 gt.irq = gpio_to_irq(gpi);
109 if (gt.irq<0) {
110 pr_info("%s: GPIO #%d IRQ is not supported\n", DRVNAME, gpi);
111 gt.irq = irq;
112 if (gt.irq >= 0) {
113 pr_info("%s: we force interrupt to IRQ %d\n", DRVNAME, gt.irq);
114 }
115 } else {
116 pr_info("%s: GPIO #%d IRQ %d is supported\n", DRVNAME, gpi, gt.irq);
117 }
118 /* gpio_direction_output must be call from task context, we use insmod as task context here */
119 err = gpio_direction_input(gpi);
120 if (err<0) {
121 pr_err("%s: GPIO #%d input direction is not possible\n", DRVNAME, gpi);
122 gpio_free(gpo);
123 gpio_free(gpi);
124 return err;
125 }
126 gt.cnt=0;
127 /* register irq handler */
128 // ToDo: Test with other flag types: IRQF_SHARED, IRQF_TRIGGER_*
129 if (gt.irq >= 0) {
130 err = request_irq(gt.irq, gpio_test_irq_handler, IRQF_TRIGGER_NONE, "gpio_test_handler", NULL);
131 if (err<0) {
132 pr_err("%s: GPIO #%d IRQ %d can not be requested, got %d\n", DRVNAME, gpi, gt.irq, err);
133 gt.irq = -1;
134 }
135 }
136 return 0;
137 }
138
139 device_initcall(gpio_test_init);
140
141 /*
142 ** just restore here the old value
143 */
144 static void __exit gpio_test_exit(void)
145 {
146 if (gt.out_cansleep) {
147 gpio_set_value_cansleep(gpo, !val);
148 } else {
149 gpio_set_value(gpo, !val);
150 }
151 if (gt.irq >= 0) free_irq(gt.irq, NULL);
152 gpio_free(gpo);
153 gpio_free(gpi);
154 }
155 module_exit(gpio_test_exit);
156
157 module_param(gpo, uint, S_IRUGO);
158 MODULE_PARM_DESC(gpo, "GPIO output address or number");
159
160 module_param(gpi, uint, S_IRUGO);
161 MODULE_PARM_DESC(gpi, "GPIO input address or number");
162
163 module_param(val, bool, S_IRUGO);
164 MODULE_PARM_DESC(val, "GPIO output value 0 or 1");
165
166 module_param(irq, uint, S_IRUGO);
167 MODULE_PARM_DESC(irq, "GPIO interrupt number");
168
169
170 MODULE_AUTHOR("Option Wireless");
171 MODULE_DESCRIPTION("GPIO output test");
172 MODULE_LICENSE("GPL");
173
174 MODULE_INFO(Version, DRIVER_VERSION);