/*
- * 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
#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;
}
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);
*/
static int gpio_irc_init(void)
{
- int i;
int res;
int dev_minor = 0;
int pom = 0;
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);
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);
}
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");