raspi_gpio_driver

annotate gpio.c @ 2:a7543d592206

- interrupt debouncing (crude) - blinking another led when pressing the button - using broadcom custom pullup/down function
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 05 Mar 2016 04:55:03 +0000
parents acfcd119e532
children
rev   line source
nuclear@0 1 #include <linux/module.h>
nuclear@0 2 #include <linux/kernel.h>
nuclear@0 3 #include <linux/io.h>
nuclear@0 4 #include <linux/fs.h>
nuclear@1 5 #include <linux/interrupt.h>
nuclear@0 6 #include <asm/uaccess.h>
nuclear@1 7 #include <linux/gpio.h>
nuclear@2 8 #include <linux/jiffies.h>
nuclear@2 9 #include <linux/platform_data/bcm2708.h>
nuclear@0 10
nuclear@1 11 #define TEST_OUTPUT_PIN 4
nuclear@2 12 #define TEST_OUTPUT_GREEN 17
nuclear@1 13 #define TEST_INPUT_PIN 22
nuclear@0 14
nuclear@1 15 static int dev_init(void);
nuclear@1 16 static void dev_exit(void);
nuclear@1 17 static int dev_open(struct inode *inode, struct file *file);
nuclear@1 18 static int dev_close(struct inode *inode, struct file *file);
nuclear@1 19 static ssize_t dev_write(struct file *file, const char *buf, size_t sz, loff_t *offset);
nuclear@0 20
nuclear@1 21 static irqreturn_t intr_handler(int inum, void *devid, struct pt_regs *regs);
nuclear@0 22
nuclear@0 23 MODULE_LICENSE("GPL");
nuclear@0 24 MODULE_AUTHOR("John Tsiombikas");
nuclear@0 25 MODULE_DESCRIPTION("gpio module");
nuclear@0 26
nuclear@1 27 module_init(dev_init);
nuclear@1 28 module_exit(dev_exit);
nuclear@0 29
nuclear@0 30 static int major;
nuclear@1 31 static int intr_num = -1;
nuclear@1 32 static int num_presses;
nuclear@0 33
nuclear@0 34 static struct file_operations ops = {
nuclear@1 35 .open = dev_open,
nuclear@1 36 .release = dev_close,
nuclear@1 37 .write = dev_write
nuclear@0 38 };
nuclear@0 39
nuclear@1 40 static int dev_init(void)
nuclear@0 41 {
nuclear@0 42 if((major = register_chrdev(0, "gpio", &ops)) < 0) {
nuclear@0 43 printk("failed to register character device gpio (err: %d)\n", major);
nuclear@0 44 return -1;
nuclear@0 45 }
nuclear@0 46 printk("gpio module registered (device: %d)\n", major);
nuclear@1 47
nuclear@1 48 gpio_direction_output(TEST_OUTPUT_PIN, 0);
nuclear@2 49 gpio_direction_output(TEST_OUTPUT_GREEN, 0);
nuclear@1 50
nuclear@1 51 if(gpio_request(TEST_INPUT_PIN, "test_input") != 0) {
nuclear@1 52 printk("gpio: failed to get input gpio pin\n");
nuclear@1 53 return -1;
nuclear@1 54 }
nuclear@2 55 gpio_direction_input(TEST_INPUT_PIN);
nuclear@2 56 bcm2708_gpio_setpull(gpio_to_chip(TEST_INPUT_PIN), TEST_INPUT_PIN, BCM2708_PULL_DOWN);
nuclear@1 57 if((intr_num = gpio_to_irq(TEST_INPUT_PIN)) < 0) {
nuclear@1 58 printk("gpio: failed to get interrupt line for gpio pin\n");
nuclear@1 59 return -1;
nuclear@1 60 }
nuclear@1 61 if(request_irq(intr_num, (irq_handler_t)intr_handler, IRQF_TRIGGER_RISING,
nuclear@1 62 "gpio_intr", "gpio") != 0) {
nuclear@1 63 printk("gpio: failed to setup interrupt handler\n");
nuclear@1 64 return -1;
nuclear@1 65 }
nuclear@1 66
nuclear@0 67 return 0;
nuclear@0 68 }
nuclear@0 69
nuclear@1 70 static void dev_exit(void)
nuclear@0 71 {
nuclear@1 72 printk("gpio exit\n");
nuclear@2 73
nuclear@0 74 unregister_chrdev(major, "gpio");
nuclear@1 75
nuclear@1 76 if(intr_num != -1) {
nuclear@1 77 free_irq(intr_num, "gpio");
nuclear@1 78 }
nuclear@1 79 gpio_free(TEST_INPUT_PIN);
nuclear@2 80
nuclear@2 81 gpio_direction_input(TEST_OUTPUT_PIN);
nuclear@2 82 gpio_direction_input(TEST_OUTPUT_GREEN);
nuclear@2 83 bcm2708_gpio_setpull(gpio_to_chip(TEST_INPUT_PIN), TEST_INPUT_PIN, BCM2708_PULL_OFF);
nuclear@0 84 }
nuclear@0 85
nuclear@1 86 static int dev_open(struct inode *inode, struct file *file)
nuclear@0 87 {
nuclear@0 88 try_module_get(THIS_MODULE);
nuclear@0 89 return 0;
nuclear@0 90 }
nuclear@0 91
nuclear@1 92 static int dev_close(struct inode *inode, struct file *file)
nuclear@0 93 {
nuclear@0 94 module_put(THIS_MODULE);
nuclear@0 95 return 0;
nuclear@0 96 }
nuclear@0 97
nuclear@1 98 static ssize_t dev_write(struct file *file, const char *buf, size_t sz, loff_t *offset)
nuclear@0 99 {
nuclear@0 100 unsigned char val;
nuclear@0 101
nuclear@0 102 if(sz < 1) {
nuclear@0 103 return 0;
nuclear@0 104 }
nuclear@0 105 if(copy_from_user(&val, (unsigned char*)buf + sz - 1, 1) != 0) {
nuclear@0 106 return -EFAULT;
nuclear@0 107 }
nuclear@0 108
nuclear@1 109 gpio_set_value(TEST_OUTPUT_PIN, val == '0' ? 0 : 1);
nuclear@0 110 return sz;
nuclear@0 111 }
nuclear@0 112
nuclear@1 113 static irqreturn_t intr_handler(int inum, void *devid, struct pt_regs *regs)
nuclear@0 114 {
nuclear@2 115 static unsigned long ignore_until;
nuclear@2 116 unsigned long now = jiffies;
nuclear@2 117
nuclear@2 118 if(time_before(now, ignore_until)) {
nuclear@2 119 return IRQ_HANDLED;
nuclear@2 120 }
nuclear@2 121 ignore_until = now + 128 * HZ / 1000;
nuclear@2 122
nuclear@1 123 printk("presses: %d\n", num_presses++);
nuclear@2 124 gpio_set_value(TEST_OUTPUT_GREEN, num_presses & 1);
nuclear@1 125 return IRQ_HANDLED;
nuclear@0 126 }