From: Pavel Pisa Date: Fri, 13 May 2016 10:42:56 +0000 (+0200) Subject: Simple software implemented IRC driver for two GPIO channels and single interrupt. X-Git-Url: https://rtime.felk.cvut.cz/gitweb/fpga/zynq/mzed-dc-control-sw.git/commitdiff_plain/642554b874d43107f7560fbb2ffcdfbaf46a831b Simple software implemented IRC driver for two GPIO channels and single interrupt. Signed-off-by: Pavel Pisa --- diff --git a/src/irc_kernel_modul/zynq_gpio_irc_module.c b/src/irc_kernel_modul/zynq_gpio_irc_module.c index 9ca7ba1..6c8e0bc 100644 --- a/src/irc_kernel_modul/zynq_gpio_irc_module.c +++ b/src/irc_kernel_modul/zynq_gpio_irc_module.c @@ -1,8 +1,8 @@ /* - * file: rpi_gpio_irc_module.c + * file: zynq_gpio_irc_module.c * * Driver for processing events on GPIO inputs and evaluation - * quadrature encoded signals to position value + * quadrature encoded signals to position value updated for Zynq experiment. * * Copyright (C) 2014 Radek Meciar * Copyright (C) 2014 Pavel Pisa @@ -35,184 +35,81 @@ Linux generic GPIO infrastructue. #include #include -#define IRC1_GPIO 23 /* GPIO 3 -> IRC channel A */ -#define IRC3_GPIO 24 +#define IRC0_A_GPIO 917 /* IRC channel A */ +#define IRC0_B_GPIO 918 /* IRC channel B */ +#define IRC0_IRQ_GPIO 906 /* IRC state change interrupt */ -#if 1 -#define IRC2_GPIO 25 /* GPIO 2 -> IRC channel B */ -#define IRC4_GPIO 27 -#else -#define IRC2_GPIO 7 /* GPIO 2 -> IRC channel B */ -#define IRC4_GPIO 8 -#endif +#define IRC0_A_NAME "GPIO906_irc0_a" +#define IRC0_B_NAME "GPIO906_irc0_b" +#define IRC0_IRQ_NAME "GPIO906_irc0_irq" -/* #define IRQ_GPIO 25 input not used for this variant of processing */ +#define IRC_GPIO_NUM 3 -#define IRC1_NAME "GPIO23_irc1_chA" -#define IRC2_NAME "GPIO7_irc2_chB" -#define IRC3_NAME "GPIO24_irc3_chA" -#define IRC4_NAME "GPI08_irc4_chB" -/* #define IRQ_name "GPIO23_irq" not used */ +#define IRC_IRQ_GPIO_INDX 2 -#define IRC_DIRECTION_DOWN -1 -#define IRC_DIRECTION_UP 1 - -#define IRC_INPUT_LOW 0 +#define IRC_INPUT_LOW 0 #define DEVICE_NAME "irc" struct gpio_irc_state { atomic_t used_count; volatile uint32_t position; + volatile uint32_t err_cnt; - volatile char prev_phase; - volatile char direction; - - int irc_gpio[4]; + unsigned prev_ab_state; - const char *irc_gpio_name[4]; - - unsigned int irc_irq_num[4]; + int irc_gpio[IRC_GPIO_NUM]; + const char *irc_gpio_name[IRC_GPIO_NUM]; + int irc_irq_num[IRC_GPIO_NUM]; }; -struct gpio_irc_state gpio_irc_0 = { - .irc_gpio = {IRC1_GPIO, IRC2_GPIO, IRC3_GPIO, IRC4_GPIO}, - .irc_gpio_name = {IRC1_NAME, IRC2_NAME, IRC3_NAME, IRC4_NAME}, +static struct gpio_irc_state gpio_irc_0 = { + .irc_gpio = {IRC0_A_GPIO, IRC0_B_GPIO, IRC0_IRQ_GPIO}, + .irc_gpio_name = {IRC0_A_NAME, IRC0_B_NAME, IRC0_IRQ_NAME}, }; int dev_major; static struct class *irc_class; -/* - * irc_irq_handlerAR: - * GPIO IRC 1 (= 3) rising edge handler - direction determined from IRC 2 (= 4). - */ -static irqreturn_t irc_irq_handlerAR(int irq, void *dev) -{ - struct gpio_irc_state *ircst = (struct gpio_irc_state *)dev; - - if (ircst->prev_phase == 0) { - ircst->position++; - ircst->prev_phase = 1; - ircst->direction = IRC_DIRECTION_UP; - return IRQ_HANDLED; - } - if (ircst->prev_phase == 3) { - ircst->position--; - ircst->prev_phase = 2; - ircst->direction = IRC_DIRECTION_DOWN; - return IRQ_HANDLED; - } +static const int irc_transitions2count[4][4] = { + { 0, 1, 0, -1}, + {-1, 0, 1, 0}, + { 0, -1, 0, 1}, + { 1, 0, -1, 0} +}; - if (gpio_get_value(ircst->irc_gpio[1]) == IRC_INPUT_LOW) { - ircst->position++; - ircst->prev_phase = 1; - ircst->direction = IRC_DIRECTION_UP; - } else { - ircst->position--; - ircst->prev_phase = 2; - ircst->direction = IRC_DIRECTION_DOWN; - } - return IRQ_HANDLED; -} +static const int irc_transitions2error[4][4] = { + { 0, 0, 1, 0}, + { 0, 0, 0, 1}, + { 1, 0, 0, 0}, + { 0, 1, 0, 0} +}; -/* - * irc_irq_handlerAF: - * GPIO IRC 3 (= 1) faling edge handler - direction determined from IRC 2 (= 4). - */ -static irqreturn_t irc_irq_handlerAF(int irq, void *dev) +static inline unsigned irc_ab_state_read(struct gpio_irc_state *ircst) { - struct gpio_irc_state *ircst = (struct gpio_irc_state *)dev; + unsigned ab; - if (ircst->prev_phase == 2) { - ircst->position++; - ircst->prev_phase = 3; - ircst->direction = IRC_DIRECTION_UP; - return IRQ_HANDLED; - } - if (ircst->prev_phase == 1) { - ircst->position--; - ircst->prev_phase = 0; - ircst->direction = IRC_DIRECTION_DOWN; - return IRQ_HANDLED; - } + ab = gpio_get_value(ircst->irc_gpio[1]) != IRC_INPUT_LOW; + ab |= ab << 1; + ab ^= gpio_get_value(ircst->irc_gpio[0]) != IRC_INPUT_LOW; - if (gpio_get_value(ircst->irc_gpio[1]) != IRC_INPUT_LOW) { - ircst->position++; - ircst->prev_phase = 3; - ircst->direction = IRC_DIRECTION_UP; - } else { - ircst->position--; - ircst->prev_phase = 0; - ircst->direction = IRC_DIRECTION_DOWN; - } - return IRQ_HANDLED; + return ab; } -/* - * irc_irq_handlerBF: - * GPIO IRC 2 (= 4) falling edge handler - direction determined from IRC 1 (= 3). - */ -static irqreturn_t irc_irq_handlerBF(int irq, void *dev) +static irqreturn_t irc_irq_handler(int irq, void *dev) { struct gpio_irc_state *ircst = (struct gpio_irc_state *)dev; + unsigned ab; + unsigned prev_ab = ircst->prev_ab_state; - if (ircst->prev_phase == 3) { - ircst->position++; - ircst->prev_phase = 0; - ircst->direction = IRC_DIRECTION_UP; - return IRQ_HANDLED; - } - if (ircst->prev_phase == 2) { - ircst->position--; - ircst->prev_phase = 1; - ircst->direction = IRC_DIRECTION_DOWN; - return IRQ_HANDLED; - } - - if (gpio_get_value(ircst->irc_gpio[0]) == IRC_INPUT_LOW) { - ircst->position++; - ircst->prev_phase = 0; - ircst->direction = IRC_DIRECTION_UP; - } else { - ircst->position--; - ircst->prev_phase = 1; - ircst->direction = IRC_DIRECTION_DOWN; - } - return IRQ_HANDLED; -} + ab = irc_ab_state_read(ircst); -/* - * irc_irq_handlerBR: - * GPIO IRC 4 (= 2) rising edge handler - direction determined from IRC 1 (= 3). - */ -static irqreturn_t irc_irq_handlerBR(int irq, void *dev) -{ - struct gpio_irc_state *ircst = (struct gpio_irc_state *)dev; + ircst->position += irc_transitions2count[prev_ab][ab]; + ircst->err_cnt += irc_transitions2error[prev_ab][ab]; - if (ircst->prev_phase == 1) { - ircst->position++; - ircst->prev_phase = 2; - ircst->direction = IRC_DIRECTION_UP; - return IRQ_HANDLED; - } - if (ircst->prev_phase == 0) { - ircst->position--; - ircst->prev_phase = 3; - ircst->direction = IRC_DIRECTION_DOWN; - return IRQ_HANDLED; - } + ircst->prev_ab_state = ab; - if (gpio_get_value(ircst->irc_gpio[0]) != IRC_INPUT_LOW) { - ircst->position++; - ircst->prev_phase = 2; - ircst->direction = IRC_DIRECTION_UP; - } else { - ircst->position--; - ircst->prev_phase = 3; - ircst->direction = IRC_DIRECTION_DOWN; - } return IRQ_HANDLED; } @@ -295,37 +192,33 @@ const struct file_operations irc_fops = { void gpio_irc_free_irq_fn(struct gpio_irc_state *ircst) { - int i; - - for (i = 0; i < 4; i++) - free_irq(ircst->irc_irq_num[i], ircst); + free_irq(ircst->irc_irq_num[IRC_IRQ_GPIO_INDX], ircst); } void gpio_irc_free_fn(struct gpio_irc_state *ircst) { int i; - for (i = 0; i < 4; i++) + for (i = 0; i < IRC_GPIO_NUM; i++) gpio_free(ircst->irc_gpio[i]); } /* * gpio_irc_setup_inputs: - * Configure inputs as sources and connect interrupt handlers - * GPIO 2, 3, 4, 23 and 24 are configured as inputs + * Configure IRC GPIOs inputs */ int gpio_irc_setup_inputs(struct gpio_irc_state *ircst) { int i; - for (i = 0; i < 4; i++) { + for (i = 0; i < IRC_GPIO_NUM; i++) { if (gpio_request(ircst->irc_gpio[i], ircst->irc_gpio_name[i]) != 0) { pr_err("failed request %s\n", ircst->irc_gpio_name[i]); goto error_gpio_request; } } - for (i = 0; i < 4; i++) { + for (i = 0; i < IRC_GPIO_NUM; i++) { if (gpio_direction_input(ircst->irc_gpio[i]) != 0) { pr_err("failed set direction input %s\n", ircst->irc_gpio_name[i]); gpio_irc_free_fn(ircst); @@ -349,7 +242,6 @@ error_gpio_request: */ static int gpio_irc_init(void) { - int i; int res; int dev_minor = 0; int pom = 0; @@ -357,8 +249,9 @@ static int gpio_irc_init(void) struct device *this_dev; pr_notice("gpio_irc init started\n"); - pr_notice("variant without table (4x IRQ on 4 GPIO) - FAST\n"); - pr_notice("for peripheral variant 2\n"); + pr_notice("variant with table (1x IRQ and %d GPIOs)\n", + IRC_GPIO_NUM); + pr_notice("for MicroZed PS MIO\n"); irc_class = class_create(THIS_MODULE, DEVICE_NAME); res = register_chrdev(dev_major, DEVICE_NAME, &irc_fops); @@ -386,47 +279,24 @@ static int gpio_irc_init(void) return (-1); } - ircst->prev_phase = -1; + ircst->prev_ab_state = irc_ab_state_read(ircst); - for (i = 0; i < 4; i++) { + { int irq_num; - irq_num = gpio_to_irq(ircst->irc_gpio[i]); + irq_num = gpio_to_irq(ircst->irc_gpio[IRC_IRQ_GPIO_INDX]); if (irq_num < 0) { - pr_err("failed get IRQ number %s\n", ircst->irc_gpio_name[i]); + pr_err("failed get IRQ number for %s\n", + ircst->irc_gpio_name[IRC_IRQ_GPIO_INDX]); gpio_irc_free_fn(ircst); return (-1); } - ircst->irc_irq_num[i] = (unsigned int)irq_num; + ircst->irc_irq_num[IRC_IRQ_GPIO_INDX] = irq_num; } - if (request_irq(ircst->irc_irq_num[0], irc_irq_handlerAR, - IRQF_TRIGGER_RISING, "irc1_irqAS", ircst) != 0) { - pr_err("failed request IRQ for %s\n", ircst->irc_gpio_name[0]); - gpio_irc_free_fn(ircst); - return (-1); - } - if (request_irq(ircst->irc_irq_num[2], irc_irq_handlerAF, - IRQF_TRIGGER_FALLING, "irc3_irqAN", ircst) != 0) { - pr_err("failed request IRQ for %s\n", ircst->irc_gpio_name[2]); - free_irq(ircst->irc_irq_num[0], ircst); - gpio_irc_free_fn(ircst); - return (-1); - } - if (request_irq(ircst->irc_irq_num[1], irc_irq_handlerBF, - IRQF_TRIGGER_FALLING, "irc2_irqBS", ircst) != 0) { - pr_err("failed request IRQ for %s\n", ircst->irc_gpio_name[1]); - free_irq(ircst->irc_irq_num[0], ircst); - free_irq(ircst->irc_irq_num[2], ircst); - gpio_irc_free_fn(ircst); - return (-1); - } - if (request_irq(ircst->irc_irq_num[3], irc_irq_handlerBR, - IRQF_TRIGGER_RISING, "irc4_irqBN", ircst) != 0) { - pr_err("failed request IRQ for %s\n", ircst->irc_gpio_name[3]); - free_irq(ircst->irc_irq_num[0], ircst); - free_irq(ircst->irc_irq_num[2], ircst); - free_irq(ircst->irc_irq_num[1], ircst); + if (request_irq(ircst->irc_irq_num[IRC_IRQ_GPIO_INDX], irc_irq_handler, + IRQF_TRIGGER_RISING, "irc_irq", ircst) != 0) { + pr_err("failed request IRQ for %s\n", ircst->irc_gpio_name[IRC_IRQ_GPIO_INDX]); gpio_irc_free_fn(ircst); return (-1); } @@ -458,4 +328,4 @@ module_exit(gpio_irc_exit); MODULE_LICENSE("GPL"); MODULE_VERSION("1.1"); MODULE_DESCRIPTION("gpio_irc module for incremetal/quadrature signals input processing"); -MODULE_AUTHOR("Radek Meciar"); +MODULE_AUTHOR("Pavel Pisa");