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 }
|