2 * file: zynq_gpio_irc_module.c
4 * Driver for processing events on GPIO inputs and evaluation
5 * quadrature encoded signals to position value updated for Zynq experiment.
7 * Copyright (C) 2014 Radek Meciar
8 * Copyright (C) 2014 Pavel Pisa
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>
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
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.
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>
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 */
42 #define IRC0_A_NAME "GPIO920_irc0_a"
43 #define IRC0_B_NAME "GPIO921_irc0_b"
44 #define IRC0_IRQ_NAME "GPIO917_irc0_irq"
46 #define IRC_GPIO_NUM 3
48 #define IRC_IRQ_GPIO_INDX 2
50 #define IRC_INPUT_LOW 0
52 #define DEVICE_NAME "irc"
54 struct gpio_irc_state {
56 volatile uint32_t position;
57 volatile uint32_t err_cnt;
59 unsigned prev_ab_state;
61 int irc_gpio[IRC_GPIO_NUM];
62 const char *irc_gpio_name[IRC_GPIO_NUM];
63 int irc_irq_num[IRC_GPIO_NUM];
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},
73 static struct class *irc_class;
75 static const int irc_transitions2count[4][4] = {
82 static const int irc_transitions2error[4][4] = {
89 static inline unsigned irc_ab_state_read(struct gpio_irc_state *ircst)
93 ab = gpio_get_value(ircst->irc_gpio[1]) != IRC_INPUT_LOW;
95 ab ^= gpio_get_value(ircst->irc_gpio[0]) != IRC_INPUT_LOW;
100 static irqreturn_t irc_irq_handler(int irq, void *dev)
102 struct gpio_irc_state *ircst = (struct gpio_irc_state *)dev;
104 unsigned prev_ab = ircst->prev_ab_state;
106 ab = irc_ab_state_read(ircst);
108 ircst->position += irc_transitions2count[prev_ab][ab];
109 ircst->err_cnt += irc_transitions2error[prev_ab][ab];
111 ircst->prev_ab_state = ab;
118 * file operation processing read systemcall for /dev/irc0 device
119 * it returns accumulated position to the calling process buffer
121 ssize_t irc_read(struct file *file, char *buffer, size_t length, loff_t *offset)
123 struct gpio_irc_state *ircst = (struct gpio_irc_state *)file->private_data;
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");
134 pos = ircst->position;
136 ret = copy_to_user(buffer, &pos, sizeof(uint32_t));
138 buffer += sizeof(uint32_t);
140 bytes_to_copy = length-sizeof(uint32_t);
144 return length - bytes_to_copy;
149 * file operation called at /dev/irc0 device open
150 * it records number of active device users
152 int irc_open(struct inode *inode, struct file *file)
154 int dev_minor = MINOR(inode->i_rdev);
155 struct gpio_irc_state *ircst = &gpio_irc_0;
158 pr_err("There is no hardware support for the device file with minor nr.: %d\n",
161 atomic_inc(&ircst->used_count);
163 file->private_data = ircst;
169 * file operation called at /dev/irc0 device close/release time
171 int irc_relase(struct inode *inode, struct file *file)
173 struct gpio_irc_state *ircst = (struct gpio_irc_state *)file->private_data;
175 if (atomic_dec_and_test(&ircst->used_count))
176 pr_debug("Last irc user finished\n");
182 *Define file operations for device IRC
184 const struct file_operations irc_fops = {
185 .owner = THIS_MODULE,
188 /* .poll = irc_poll,*/
190 .release = irc_relase,
193 void gpio_irc_free_irq_fn(struct gpio_irc_state *ircst)
195 free_irq(ircst->irc_irq_num[IRC_IRQ_GPIO_INDX], ircst);
198 void gpio_irc_free_fn(struct gpio_irc_state *ircst)
202 for (i = 0; i < IRC_GPIO_NUM; i++)
203 gpio_free(ircst->irc_gpio[i]);
207 * gpio_irc_setup_inputs:
208 * Configure IRC GPIOs inputs
210 int gpio_irc_setup_inputs(struct gpio_irc_state *ircst)
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;
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);
234 gpio_free(ircst->irc_gpio[--i]);
241 * Module initialization.
243 static int gpio_irc_init(void)
248 struct gpio_irc_state *ircst = &gpio_irc_0;
249 struct device *this_dev;
251 pr_notice("gpio_irc init started\n");
252 pr_notice("variant with table (1x IRQ and %d GPIOs)\n",
254 pr_notice("for MicroZed PS MIO\n");
256 irc_class = class_create(THIS_MODULE, DEVICE_NAME);
257 res = register_chrdev(dev_major, DEVICE_NAME, &irc_fops);
259 pr_err("Error registering driver.\n");
260 class_destroy(irc_class);
262 /*goto register_error;*/
267 this_dev = device_create(irc_class, NULL, MKDEV(dev_major, dev_minor),
268 NULL, "irc%d", dev_minor);
270 if (IS_ERR(this_dev)) {
271 pr_err("problem to create device \"irc%d\" in the class \"irc\"\n",
276 pom = gpio_irc_setup_inputs(ircst);
278 pr_err("Inicializace GPIO se nezdarila");
282 ircst->prev_ab_state = irc_ab_state_read(ircst);
287 irq_num = gpio_to_irq(ircst->irc_gpio[IRC_IRQ_GPIO_INDX]);
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);
294 ircst->irc_irq_num[IRC_IRQ_GPIO_INDX] = irq_num;
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);
303 pr_notice("gpio_irc init done\n");
309 * Called when module is removed.
311 static void gpio_irc_exit(void)
313 struct gpio_irc_state *ircst = &gpio_irc_0;
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);
322 pr_notice("gpio_irc modul closed\n");
325 module_init(gpio_irc_init);
326 module_exit(gpio_irc_exit);
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");