]> rtime.felk.cvut.cz Git - fpga/zynq/mzed-dc-control-sw.git/blob - src/irc_kernel_modul/zynq_gpio_irc_module.c
79c57707f3d1343ba0633cf4a0b42976793cc117
[fpga/zynq/mzed-dc-control-sw.git] / src / irc_kernel_modul / zynq_gpio_irc_module.c
1 /*
2  *  file: zynq_gpio_irc_module.c
3  *
4  *  Driver for processing events on GPIO inputs and evaluation
5  *  quadrature encoded signals to position value updated for Zynq experiment.
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 IRC0_A_GPIO     920 /* IRC channel A */
39 #define IRC0_B_GPIO     921 /* IRC channel B */
40 #define IRC0_IRQ_GPIO   917 /* IRC state change interrupt */
41
42 #define IRC0_A_NAME     "GPIO920_irc0_a"
43 #define IRC0_B_NAME     "GPIO921_irc0_b"
44 #define IRC0_IRQ_NAME   "GPIO917_irc0_irq"
45
46 #define IRC_GPIO_NUM    3
47
48 #define IRC_IRQ_GPIO_INDX 2
49
50 #define IRC_INPUT_LOW   0
51
52 #define DEVICE_NAME     "irc"
53
54 struct gpio_irc_state {
55         atomic_t used_count;
56         volatile uint32_t position;
57         volatile uint32_t err_cnt;
58
59         unsigned prev_ab_state;
60
61         int irc_gpio[IRC_GPIO_NUM];
62         const char *irc_gpio_name[IRC_GPIO_NUM];
63         int irc_irq_num[IRC_GPIO_NUM];
64 };
65
66 static struct gpio_irc_state gpio_irc_0 = {
67         .irc_gpio =      {IRC0_A_GPIO, IRC0_B_GPIO, IRC0_IRQ_GPIO},
68         .irc_gpio_name = {IRC0_A_NAME, IRC0_B_NAME, IRC0_IRQ_NAME},
69 };
70
71 int dev_major;
72
73 static struct class *irc_class;
74
75 static const int irc_transitions2count[4][4] = {
76   { 0,  1,  0, -1},
77   {-1,  0,  1,  0},
78   { 0, -1,  0,  1},
79   { 1,  0, -1,  0}
80 };
81
82 static const int irc_transitions2error[4][4] = {
83   { 0,  0,  1,  0},
84   { 0,  0,  0,  1},
85   { 1,  0,  0,  0},
86   { 0,  1,  0,  0}
87 };
88
89 static inline unsigned irc_ab_state_read(struct gpio_irc_state *ircst)
90 {
91         unsigned ab;
92
93         ab = gpio_get_value(ircst->irc_gpio[1]) != IRC_INPUT_LOW;
94         ab |= ab << 1;
95         ab ^= gpio_get_value(ircst->irc_gpio[0]) != IRC_INPUT_LOW;
96
97         return ab;
98 }
99
100 static irqreturn_t irc_irq_handler(int irq, void *dev)
101 {
102         struct gpio_irc_state *ircst = (struct gpio_irc_state *)dev;
103         unsigned ab;
104         unsigned prev_ab = ircst->prev_ab_state;
105
106         ab = irc_ab_state_read(ircst);
107
108         ircst->position += irc_transitions2count[prev_ab][ab];
109         ircst->err_cnt += irc_transitions2error[prev_ab][ab];
110
111         ircst->prev_ab_state = ab;
112
113         return IRQ_HANDLED;
114 }
115
116 /*
117  * irc_read:
118  *      file operation processing read systemcall for /dev/irc0 device
119  *      it returns accumulated position to the calling process buffer
120  */
121 ssize_t irc_read(struct file *file, char *buffer, size_t length, loff_t *offset)
122 {
123         struct gpio_irc_state *ircst = (struct gpio_irc_state *)file->private_data;
124         int bytes_to_copy;
125         int ret;
126         uint32_t pos;
127
128         if (length < sizeof(uint32_t)) {
129                 pr_debug("Trying to read less bytes than a irc message,\n");
130                 pr_debug("this will always return zero.\n");
131                 return 0;
132         }
133
134         pos = ircst->position;
135
136         ret = copy_to_user(buffer, &pos, sizeof(uint32_t));
137
138         buffer += sizeof(uint32_t);
139
140         bytes_to_copy = length-sizeof(uint32_t);
141         if (ret)
142                 return -EFAULT;
143
144         return length - bytes_to_copy;
145 }
146
147 /*
148  * irc_open:
149  *      file operation called at /dev/irc0 device open
150  *      it records number of active device users
151  */
152 int irc_open(struct inode *inode, struct file *file)
153 {
154         int dev_minor = MINOR(inode->i_rdev);
155         struct gpio_irc_state *ircst = &gpio_irc_0;
156
157         if (dev_minor > 0)
158                 pr_err("There is no hardware support for the device file with minor nr.: %d\n",
159                         dev_minor);
160
161         atomic_inc(&ircst->used_count);
162
163         file->private_data = ircst;
164         return 0;
165 }
166
167 /*
168  *irc_relese:
169  *      file operation called at /dev/irc0 device close/release time
170  */
171 int irc_relase(struct inode *inode, struct file *file)
172 {
173         struct gpio_irc_state *ircst = (struct gpio_irc_state *)file->private_data;
174
175         if (atomic_dec_and_test(&ircst->used_count))
176                 pr_debug("Last irc user finished\n");
177
178         return 0;
179 }
180
181 /*
182  *Define file operations for device IRC
183  */
184 const struct file_operations irc_fops = {
185         .owner = THIS_MODULE,
186         .read = irc_read,
187         .write = NULL,
188 /*      .poll = irc_poll,*/
189         .open = irc_open,
190         .release = irc_relase,
191 };
192
193 void gpio_irc_free_irq_fn(struct gpio_irc_state *ircst)
194 {
195         free_irq(ircst->irc_irq_num[IRC_IRQ_GPIO_INDX], ircst);
196 }
197
198 void gpio_irc_free_fn(struct gpio_irc_state *ircst)
199 {
200         int i;
201
202         for (i = 0; i < IRC_GPIO_NUM; i++)
203                 gpio_free(ircst->irc_gpio[i]);
204 }
205
206 /*
207  * gpio_irc_setup_inputs:
208  *      Configure IRC GPIOs inputs
209  */
210 int gpio_irc_setup_inputs(struct gpio_irc_state *ircst)
211 {
212         int i;
213
214         for (i = 0; i < IRC_GPIO_NUM; i++) {
215                 if (gpio_request(ircst->irc_gpio[i], ircst->irc_gpio_name[i]) != 0) {
216                         pr_err("failed request %s\n", ircst->irc_gpio_name[i]);
217                         goto error_gpio_request;
218                 }
219         }
220
221         for (i = 0; i < IRC_GPIO_NUM; i++) {
222                 if (gpio_direction_input(ircst->irc_gpio[i]) != 0) {
223                         pr_err("failed set direction input %s\n", ircst->irc_gpio_name[i]);
224                         gpio_irc_free_fn(ircst);
225                         return (-1);
226                 }
227         }
228
229         return 0;
230
231 error_gpio_request:
232
233         while (i > 0)
234                 gpio_free(ircst->irc_gpio[--i]);
235
236         return -1;
237 }
238
239 /*
240  * gpio_irc_init:
241  *      Module initialization.
242  */
243 static int gpio_irc_init(void)
244 {
245         int res;
246         int dev_minor = 0;
247         int pom = 0;
248         struct gpio_irc_state *ircst = &gpio_irc_0;
249         struct device *this_dev;
250
251         pr_notice("gpio_irc init started\n");
252         pr_notice("variant with table (1x IRQ and %d GPIOs)\n",
253                   IRC_GPIO_NUM);
254         pr_notice("for MicroZed PS MIO\n");
255
256         irc_class = class_create(THIS_MODULE, DEVICE_NAME);
257         res = register_chrdev(dev_major, DEVICE_NAME, &irc_fops);
258         if (res < 0) {
259                 pr_err("Error registering driver.\n");
260                 class_destroy(irc_class);
261                 return -ENODEV;
262                 /*goto register_error;*/
263         }
264         if (dev_major == 0)
265                 dev_major = res;
266
267         this_dev = device_create(irc_class, NULL, MKDEV(dev_major, dev_minor),
268                                 NULL,  "irc%d", dev_minor);
269
270         if (IS_ERR(this_dev)) {
271                 pr_err("problem to create device \"irc%d\" in the class \"irc\"\n",
272                         dev_minor);
273                 return (-1);
274         }
275
276         pom = gpio_irc_setup_inputs(ircst);
277         if (pom == -1) {
278                 pr_err("Inicializace GPIO se nezdarila");
279                 return (-1);
280         }
281
282         ircst->prev_ab_state = irc_ab_state_read(ircst);
283
284         {
285                 int irq_num;
286
287                 irq_num = gpio_to_irq(ircst->irc_gpio[IRC_IRQ_GPIO_INDX]);
288                 if (irq_num < 0) {
289                         pr_err("failed get IRQ number for %s\n",
290                                 ircst->irc_gpio_name[IRC_IRQ_GPIO_INDX]);
291                         gpio_irc_free_fn(ircst);
292                         return (-1);
293                 }
294                 ircst->irc_irq_num[IRC_IRQ_GPIO_INDX] = irq_num;
295         }
296
297         if (request_irq(ircst->irc_irq_num[IRC_IRQ_GPIO_INDX], irc_irq_handler,
298                         IRQF_TRIGGER_RISING, "irc_irq", ircst) != 0) {
299                 pr_err("failed request IRQ for %s\n", ircst->irc_gpio_name[IRC_IRQ_GPIO_INDX]);
300                 gpio_irc_free_fn(ircst);
301                 return (-1);
302         }
303         pr_notice("gpio_irc init done\n");
304         return 0;
305 }
306
307 /*
308  * gpio_irc_exist:
309  *      Called when module is removed.
310  */
311 static void gpio_irc_exit(void)
312 {
313         struct gpio_irc_state *ircst = &gpio_irc_0;
314         int dev_minor = 0;
315
316         gpio_irc_free_irq_fn(ircst);
317         gpio_irc_free_fn(ircst);
318         device_destroy(irc_class, MKDEV(dev_major, dev_minor));
319         class_destroy(irc_class);
320         unregister_chrdev(dev_major, DEVICE_NAME);
321
322         pr_notice("gpio_irc modul closed\n");
323 }
324
325 module_init(gpio_irc_init);
326 module_exit(gpio_irc_exit);
327
328 MODULE_LICENSE("GPL");
329 MODULE_VERSION("1.1");
330 MODULE_DESCRIPTION("gpio_irc module for incremetal/quadrature signals input processing");
331 MODULE_AUTHOR("Pavel Pisa");