]> rtime.felk.cvut.cz Git - fpga/zynq/mzed-dc-control-sw.git/blob - src/irc_kernel_modul/zynq_gpio_irc_module.c
Add copy of Raspberry Pi software realized IRC processing.
[fpga/zynq/mzed-dc-control-sw.git] / src / irc_kernel_modul / zynq_gpio_irc_module.c
1 /*
2  *  file: rpi_gpio_irc_module.c
3  *
4  *  Driver for processing events on GPIO inputs and evaluation
5  *  quadrature encoded signals to position value
6  *
7  *  Copyright (C) 2014 Radek Meciar
8  *  Copyright (C) 2014 Pavel Pisa
9  *
10  *  More information in bachelor thesis
11  *    Motor control with Raspberry Pi board and Linux
12  *    https://support.dce.felk.cvut.cz/mediawiki/images/1/10/Bp_2014_meciar_radek.pdf
13  *  Supervisor: Pavel Pisa <pisa@cmp.felk.cvut.cz>
14  *
15  *  This file is subject to the terms and conditions of the GNU General Public
16  *  License.  See the file COPYING in the main directory of this archive
17  *  for more details.
18  */
19
20 /*
21 IRC inputs are mapped to GPIO 7, 8, 23, 24 on RPI P1.
22 The channel A is mapped to inputs 7 and 8, channel B to 23 and 24.
23 Mapping of each signal to two inputs (one configured for IRQ on
24 signal rising edge and another for falling edge)
25 simplifies evaluation because there is no need to read actual
26 GPIO values which posses considerable overhead through
27 Linux generic GPIO infrastructue.
28 */
29
30 #include <linux/init.h>
31 #include <linux/module.h>
32 #include <linux/gpio.h>
33 #include <linux/interrupt.h>
34 #include <linux/proc_fs.h>
35 #include <linux/uaccess.h>
36 #include <linux/device.h>
37
38 #define IRC1_GPIO       23 /* GPIO 3 -> IRC channel A */
39 #define IRC3_GPIO       24
40
41 #if 1
42 #define IRC2_GPIO       25 /* GPIO 2 -> IRC channel B */
43 #define IRC4_GPIO       27
44 #else
45 #define IRC2_GPIO       7 /* GPIO 2 -> IRC channel B */
46 #define IRC4_GPIO       8
47 #endif
48
49 /* #define IRQ_GPIO     25 input not used for this variant of processing */
50
51 #define IRC1_NAME       "GPIO23_irc1_chA"
52 #define IRC2_NAME       "GPIO7_irc2_chB"
53 #define IRC3_NAME       "GPIO24_irc3_chA"
54 #define IRC4_NAME       "GPI08_irc4_chB"
55 /* #define IRQ_name     "GPIO23_irq" not used */
56
57 #define IRC_DIRECTION_DOWN      -1
58 #define IRC_DIRECTION_UP        1
59
60 #define IRC_INPUT_LOW           0
61
62 #define DEVICE_NAME     "irc"
63
64 struct gpio_irc_state {
65         atomic_t used_count;
66         volatile uint32_t position;
67
68         volatile char prev_phase;
69         volatile char direction;
70
71         int irc_gpio[4];
72
73         const char *irc_gpio_name[4];
74
75         unsigned int irc_irq_num[4];
76 };
77
78 struct gpio_irc_state gpio_irc_0 = {
79         .irc_gpio =      {IRC1_GPIO, IRC2_GPIO, IRC3_GPIO, IRC4_GPIO},
80         .irc_gpio_name = {IRC1_NAME, IRC2_NAME, IRC3_NAME, IRC4_NAME},
81 };
82
83 int dev_major;
84
85 static struct class *irc_class;
86
87 /*
88  * irc_irq_handlerAR:
89  *      GPIO IRC 1 (= 3) rising edge handler - direction determined from IRC 2 (= 4).
90  */
91 static irqreturn_t irc_irq_handlerAR(int irq, void *dev)
92 {
93         struct gpio_irc_state *ircst = (struct gpio_irc_state *)dev;
94
95         if (ircst->prev_phase == 0) {
96                 ircst->position++;
97                 ircst->prev_phase = 1;
98                 ircst->direction = IRC_DIRECTION_UP;
99                 return IRQ_HANDLED;
100         }
101         if (ircst->prev_phase == 3) {
102                 ircst->position--;
103                 ircst->prev_phase = 2;
104                 ircst->direction = IRC_DIRECTION_DOWN;
105                 return IRQ_HANDLED;
106         }
107
108         if (gpio_get_value(ircst->irc_gpio[1]) == IRC_INPUT_LOW) {
109                 ircst->position++;
110                 ircst->prev_phase = 1;
111                 ircst->direction = IRC_DIRECTION_UP;
112         } else {
113                 ircst->position--;
114                 ircst->prev_phase = 2;
115                 ircst->direction = IRC_DIRECTION_DOWN;
116         }
117         return IRQ_HANDLED;
118 }
119
120 /*
121  * irc_irq_handlerAF:
122  *      GPIO IRC 3 (= 1) faling edge handler - direction determined from IRC 2 (= 4).
123  */
124 static irqreturn_t irc_irq_handlerAF(int irq, void *dev)
125 {
126         struct gpio_irc_state *ircst = (struct gpio_irc_state *)dev;
127
128         if (ircst->prev_phase == 2) {
129                 ircst->position++;
130                 ircst->prev_phase = 3;
131                 ircst->direction = IRC_DIRECTION_UP;
132                 return IRQ_HANDLED;
133         }
134         if (ircst->prev_phase == 1) {
135                 ircst->position--;
136                 ircst->prev_phase = 0;
137                 ircst->direction = IRC_DIRECTION_DOWN;
138                 return IRQ_HANDLED;
139         }
140
141         if (gpio_get_value(ircst->irc_gpio[1]) != IRC_INPUT_LOW) {
142                 ircst->position++;
143                 ircst->prev_phase = 3;
144                 ircst->direction = IRC_DIRECTION_UP;
145         } else {
146                 ircst->position--;
147                 ircst->prev_phase = 0;
148                 ircst->direction = IRC_DIRECTION_DOWN;
149         }
150         return IRQ_HANDLED;
151 }
152
153 /*
154  * irc_irq_handlerBF:
155  *      GPIO IRC 2 (= 4) falling edge handler - direction determined from IRC 1 (= 3).
156  */
157 static irqreturn_t irc_irq_handlerBF(int irq, void *dev)
158 {
159         struct gpio_irc_state *ircst = (struct gpio_irc_state *)dev;
160
161         if (ircst->prev_phase == 3) {
162                 ircst->position++;
163                 ircst->prev_phase = 0;
164                 ircst->direction = IRC_DIRECTION_UP;
165                 return IRQ_HANDLED;
166         }
167         if (ircst->prev_phase == 2) {
168                 ircst->position--;
169                 ircst->prev_phase = 1;
170                 ircst->direction = IRC_DIRECTION_DOWN;
171                 return IRQ_HANDLED;
172         }
173
174         if (gpio_get_value(ircst->irc_gpio[0]) == IRC_INPUT_LOW) {
175                 ircst->position++;
176                 ircst->prev_phase = 0;
177                 ircst->direction = IRC_DIRECTION_UP;
178         } else {
179                 ircst->position--;
180                 ircst->prev_phase = 1;
181                 ircst->direction = IRC_DIRECTION_DOWN;
182         }
183         return IRQ_HANDLED;
184 }
185
186 /*
187  * irc_irq_handlerBR:
188  *      GPIO IRC 4 (= 2) rising edge handler - direction determined from IRC 1 (= 3).
189  */
190 static irqreturn_t irc_irq_handlerBR(int irq, void *dev)
191 {
192         struct gpio_irc_state *ircst = (struct gpio_irc_state *)dev;
193
194         if (ircst->prev_phase == 1) {
195                 ircst->position++;
196                 ircst->prev_phase = 2;
197                 ircst->direction = IRC_DIRECTION_UP;
198                 return IRQ_HANDLED;
199         }
200         if (ircst->prev_phase == 0) {
201                 ircst->position--;
202                 ircst->prev_phase = 3;
203                 ircst->direction = IRC_DIRECTION_DOWN;
204                 return IRQ_HANDLED;
205         }
206
207         if (gpio_get_value(ircst->irc_gpio[0]) != IRC_INPUT_LOW) {
208                 ircst->position++;
209                 ircst->prev_phase = 2;
210                 ircst->direction = IRC_DIRECTION_UP;
211         } else {
212                 ircst->position--;
213                 ircst->prev_phase = 3;
214                 ircst->direction = IRC_DIRECTION_DOWN;
215         }
216         return IRQ_HANDLED;
217 }
218
219 /*
220  * irc_read:
221  *      file operation processing read systemcall for /dev/irc0 device
222  *      it returns accumulated position to the calling process buffer
223  */
224 ssize_t irc_read(struct file *file, char *buffer, size_t length, loff_t *offset)
225 {
226         struct gpio_irc_state *ircst = (struct gpio_irc_state *)file->private_data;
227         int bytes_to_copy;
228         int ret;
229         uint32_t pos;
230
231         if (length < sizeof(uint32_t)) {
232                 pr_debug("Trying to read less bytes than a irc message,\n");
233                 pr_debug("this will always return zero.\n");
234                 return 0;
235         }
236
237         pos = ircst->position;
238
239         ret = copy_to_user(buffer, &pos, sizeof(uint32_t));
240
241         buffer += sizeof(uint32_t);
242
243         bytes_to_copy = length-sizeof(uint32_t);
244         if (ret)
245                 return -EFAULT;
246
247         return length - bytes_to_copy;
248 }
249
250 /*
251  * irc_open:
252  *      file operation called at /dev/irc0 device open
253  *      it records number of active device users
254  */
255 int irc_open(struct inode *inode, struct file *file)
256 {
257         int dev_minor = MINOR(inode->i_rdev);
258         struct gpio_irc_state *ircst = &gpio_irc_0;
259
260         if (dev_minor > 0)
261                 pr_err("There is no hardware support for the device file with minor nr.: %d\n",
262                         dev_minor);
263
264         atomic_inc(&ircst->used_count);
265
266         file->private_data = ircst;
267         return 0;
268 }
269
270 /*
271  *irc_relese:
272  *      file operation called at /dev/irc0 device close/release time
273  */
274 int irc_relase(struct inode *inode, struct file *file)
275 {
276         struct gpio_irc_state *ircst = (struct gpio_irc_state *)file->private_data;
277
278         if (atomic_dec_and_test(&ircst->used_count))
279                 pr_debug("Last irc user finished\n");
280
281         return 0;
282 }
283
284 /*
285  *Define file operations for device IRC
286  */
287 const struct file_operations irc_fops = {
288         .owner = THIS_MODULE,
289         .read = irc_read,
290         .write = NULL,
291 /*      .poll = irc_poll,*/
292         .open = irc_open,
293         .release = irc_relase,
294 };
295
296 void gpio_irc_free_irq_fn(struct gpio_irc_state *ircst)
297 {
298         int i;
299
300         for (i = 0; i < 4; i++)
301                 free_irq(ircst->irc_irq_num[i], ircst);
302 }
303
304 void gpio_irc_free_fn(struct gpio_irc_state *ircst)
305 {
306         int i;
307
308         for (i = 0; i < 4; i++)
309                 gpio_free(ircst->irc_gpio[i]);
310 }
311
312 /*
313  * gpio_irc_setup_inputs:
314  *      Configure inputs as sources and connect interrupt handlers
315  *      GPIO 2, 3, 4, 23 and 24 are configured as inputs
316  */
317 int gpio_irc_setup_inputs(struct gpio_irc_state *ircst)
318 {
319         int i;
320
321         for (i = 0; i < 4; i++) {
322                 if (gpio_request(ircst->irc_gpio[i], ircst->irc_gpio_name[i]) != 0) {
323                         pr_err("failed request %s\n", ircst->irc_gpio_name[i]);
324                         goto error_gpio_request;
325                 }
326         }
327
328         for (i = 0; i < 4; i++) {
329                 if (gpio_direction_input(ircst->irc_gpio[i]) != 0) {
330                         pr_err("failed set direction input %s\n", ircst->irc_gpio_name[i]);
331                         gpio_irc_free_fn(ircst);
332                         return (-1);
333                 }
334         }
335
336         return 0;
337
338 error_gpio_request:
339
340         while (i > 0)
341                 gpio_free(ircst->irc_gpio[--i]);
342
343         return -1;
344 }
345
346 /*
347  * gpio_irc_init:
348  *      Module initialization.
349  */
350 static int gpio_irc_init(void)
351 {
352         int i;
353         int res;
354         int dev_minor = 0;
355         int pom = 0;
356         struct gpio_irc_state *ircst = &gpio_irc_0;
357         struct device *this_dev;
358
359         pr_notice("gpio_irc init started\n");
360         pr_notice("variant without table (4x IRQ on 4 GPIO) - FAST\n");
361         pr_notice("for peripheral variant 2\n");
362
363         irc_class = class_create(THIS_MODULE, DEVICE_NAME);
364         res = register_chrdev(dev_major, DEVICE_NAME, &irc_fops);
365         if (res < 0) {
366                 pr_err("Error registering driver.\n");
367                 class_destroy(irc_class);
368                 return -ENODEV;
369                 /*goto register_error;*/
370         }
371         if (dev_major == 0)
372                 dev_major = res;
373
374         this_dev = device_create(irc_class, NULL, MKDEV(dev_major, dev_minor),
375                                 NULL,  "irc%d", dev_minor);
376
377         if (IS_ERR(this_dev)) {
378                 pr_err("problem to create device \"irc%d\" in the class \"irc\"\n",
379                         dev_minor);
380                 return (-1);
381         }
382
383         pom = gpio_irc_setup_inputs(ircst);
384         if (pom == -1) {
385                 pr_err("Inicializace GPIO se nezdarila");
386                 return (-1);
387         }
388
389         ircst->prev_phase = -1;
390
391         for (i = 0; i < 4; i++) {
392                 int irq_num;
393
394                 irq_num = gpio_to_irq(ircst->irc_gpio[i]);
395                 if (irq_num < 0) {
396                         pr_err("failed get IRQ number %s\n", ircst->irc_gpio_name[i]);
397                         gpio_irc_free_fn(ircst);
398                         return (-1);
399                 }
400                 ircst->irc_irq_num[i] = (unsigned int)irq_num;
401         }
402
403         if (request_irq(ircst->irc_irq_num[0], irc_irq_handlerAR,
404                         IRQF_TRIGGER_RISING, "irc1_irqAS", ircst) != 0) {
405                 pr_err("failed request IRQ for %s\n", ircst->irc_gpio_name[0]);
406                 gpio_irc_free_fn(ircst);
407                 return (-1);
408         }
409         if (request_irq(ircst->irc_irq_num[2], irc_irq_handlerAF,
410                         IRQF_TRIGGER_FALLING, "irc3_irqAN", ircst) != 0) {
411                 pr_err("failed request IRQ for %s\n", ircst->irc_gpio_name[2]);
412                 free_irq(ircst->irc_irq_num[0], ircst);
413                 gpio_irc_free_fn(ircst);
414                 return (-1);
415         }
416         if (request_irq(ircst->irc_irq_num[1], irc_irq_handlerBF,
417                         IRQF_TRIGGER_FALLING, "irc2_irqBS", ircst) != 0) {
418                 pr_err("failed request IRQ for %s\n", ircst->irc_gpio_name[1]);
419                 free_irq(ircst->irc_irq_num[0], ircst);
420                 free_irq(ircst->irc_irq_num[2], ircst);
421                 gpio_irc_free_fn(ircst);
422                 return (-1);
423         }
424         if (request_irq(ircst->irc_irq_num[3], irc_irq_handlerBR,
425                         IRQF_TRIGGER_RISING, "irc4_irqBN", ircst) != 0) {
426                 pr_err("failed request IRQ for %s\n", ircst->irc_gpio_name[3]);
427                 free_irq(ircst->irc_irq_num[0], ircst);
428                 free_irq(ircst->irc_irq_num[2], ircst);
429                 free_irq(ircst->irc_irq_num[1], ircst);
430                 gpio_irc_free_fn(ircst);
431                 return (-1);
432         }
433         pr_notice("gpio_irc init done\n");
434         return 0;
435 }
436
437 /*
438  * gpio_irc_exist:
439  *      Called when module is removed.
440  */
441 static void gpio_irc_exit(void)
442 {
443         struct gpio_irc_state *ircst = &gpio_irc_0;
444         int dev_minor = 0;
445
446         gpio_irc_free_irq_fn(ircst);
447         gpio_irc_free_fn(ircst);
448         device_destroy(irc_class, MKDEV(dev_major, dev_minor));
449         class_destroy(irc_class);
450         unregister_chrdev(dev_major, DEVICE_NAME);
451
452         pr_notice("gpio_irc modul closed\n");
453 }
454
455 module_init(gpio_irc_init);
456 module_exit(gpio_irc_exit);
457
458 MODULE_LICENSE("GPL");
459 MODULE_VERSION("1.1");
460 MODULE_DESCRIPTION("gpio_irc module for incremetal/quadrature signals input processing");
461 MODULE_AUTHOR("Radek Meciar");