raspi_gpio_driver

annotate gpio.c @ 1:acfcd119e532

- dropped all my custom i/o register fiddling in favor of the kernel gpio functions which are already implemented by broadcom. - added a test interrupt handler
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 05 Mar 2016 04:25:33 +0000
parents fbab2b3e28da
children a7543d592206
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@0 8
nuclear@1 9 #define TEST_OUTPUT_PIN 4
nuclear@1 10 #define TEST_INPUT_PIN 22
nuclear@0 11
nuclear@1 12 static int dev_init(void);
nuclear@1 13 static void dev_exit(void);
nuclear@1 14 static int dev_open(struct inode *inode, struct file *file);
nuclear@1 15 static int dev_close(struct inode *inode, struct file *file);
nuclear@1 16 static ssize_t dev_write(struct file *file, const char *buf, size_t sz, loff_t *offset);
nuclear@0 17
nuclear@1 18 static irqreturn_t intr_handler(int inum, void *devid, struct pt_regs *regs);
nuclear@0 19
nuclear@0 20 MODULE_LICENSE("GPL");
nuclear@0 21 MODULE_AUTHOR("John Tsiombikas");
nuclear@0 22 MODULE_DESCRIPTION("gpio module");
nuclear@0 23
nuclear@1 24 module_init(dev_init);
nuclear@1 25 module_exit(dev_exit);
nuclear@0 26
nuclear@0 27 static int major;
nuclear@1 28 static int intr_num = -1;
nuclear@1 29 static int num_presses;
nuclear@0 30
nuclear@0 31 static struct file_operations ops = {
nuclear@1 32 .open = dev_open,
nuclear@1 33 .release = dev_close,
nuclear@1 34 .write = dev_write
nuclear@0 35 };
nuclear@0 36
nuclear@1 37 static int dev_init(void)
nuclear@0 38 {
nuclear@0 39 if((major = register_chrdev(0, "gpio", &ops)) < 0) {
nuclear@0 40 printk("failed to register character device gpio (err: %d)\n", major);
nuclear@0 41 return -1;
nuclear@0 42 }
nuclear@0 43 printk("gpio module registered (device: %d)\n", major);
nuclear@1 44
nuclear@1 45 gpio_direction_output(TEST_OUTPUT_PIN, 0);
nuclear@1 46 gpio_direction_input(TEST_INPUT_PIN);
nuclear@1 47
nuclear@1 48 if(gpio_request(TEST_INPUT_PIN, "test_input") != 0) {
nuclear@1 49 printk("gpio: failed to get input gpio pin\n");
nuclear@1 50 return -1;
nuclear@1 51 }
nuclear@1 52 if((intr_num = gpio_to_irq(TEST_INPUT_PIN)) < 0) {
nuclear@1 53 printk("gpio: failed to get interrupt line for gpio pin\n");
nuclear@1 54 return -1;
nuclear@1 55 }
nuclear@1 56 if(request_irq(intr_num, (irq_handler_t)intr_handler, IRQF_TRIGGER_RISING,
nuclear@1 57 "gpio_intr", "gpio") != 0) {
nuclear@1 58 printk("gpio: failed to setup interrupt handler\n");
nuclear@1 59 return -1;
nuclear@1 60 }
nuclear@1 61
nuclear@0 62 return 0;
nuclear@0 63 }
nuclear@0 64
nuclear@1 65 static void dev_exit(void)
nuclear@0 66 {
nuclear@1 67 printk("gpio exit\n");
nuclear@0 68 unregister_chrdev(major, "gpio");
nuclear@1 69
nuclear@1 70 if(intr_num != -1) {
nuclear@1 71 free_irq(intr_num, "gpio");
nuclear@1 72 }
nuclear@1 73 gpio_free(TEST_INPUT_PIN);
nuclear@0 74 }
nuclear@0 75
nuclear@1 76 static int dev_open(struct inode *inode, struct file *file)
nuclear@0 77 {
nuclear@0 78 try_module_get(THIS_MODULE);
nuclear@0 79 return 0;
nuclear@0 80 }
nuclear@0 81
nuclear@1 82 static int dev_close(struct inode *inode, struct file *file)
nuclear@0 83 {
nuclear@0 84 module_put(THIS_MODULE);
nuclear@0 85 return 0;
nuclear@0 86 }
nuclear@0 87
nuclear@1 88 static ssize_t dev_write(struct file *file, const char *buf, size_t sz, loff_t *offset)
nuclear@0 89 {
nuclear@0 90 unsigned char val;
nuclear@0 91
nuclear@1 92 printk("dev_write(%d) called\n", sz);
nuclear@0 93
nuclear@0 94 if(sz < 1) {
nuclear@0 95 return 0;
nuclear@0 96 }
nuclear@0 97 if(copy_from_user(&val, (unsigned char*)buf + sz - 1, 1) != 0) {
nuclear@0 98 return -EFAULT;
nuclear@0 99 }
nuclear@0 100
nuclear@1 101 gpio_set_value(TEST_OUTPUT_PIN, val == '0' ? 0 : 1);
nuclear@0 102 return sz;
nuclear@0 103 }
nuclear@0 104
nuclear@1 105 static irqreturn_t intr_handler(int inum, void *devid, struct pt_regs *regs)
nuclear@0 106 {
nuclear@1 107 printk("presses: %d\n", num_presses++);
nuclear@1 108 return IRQ_HANDLED;
nuclear@0 109 }