]> rtime.felk.cvut.cz Git - fpga/zynq/mzed-dc-control-sw.git/commitdiff
Simple software implemented IRC driver for two GPIO channels and single interrupt.
authorPavel Pisa <pisa@cmp.felk.cvut.cz>
Fri, 13 May 2016 10:42:56 +0000 (12:42 +0200)
committerPavel Pisa <pisa@cmp.felk.cvut.cz>
Fri, 13 May 2016 10:42:56 +0000 (12:42 +0200)
Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
src/irc_kernel_modul/zynq_gpio_irc_module.c

index 9ca7ba1085b0bc5b02b2a6bb92fb5c18144f3585..6c8e0bcd2bf4057f64eaf0415611d03b406ec1e6 100644 (file)
@@ -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 <linux/uaccess.h>
 #include <linux/device.h>
 
-#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");