root / scout_gumstix / encoder / encoder.c @ 2b0ba4bb
History | View | Annotate | Download (4.97 KB)
1 | 83163372 | Tom Mullins | #include <linux/init.h> |
---|---|---|---|
2 | #include <linux/module.h> |
||
3 | #include <linux/fs.h> |
||
4 | #include <linux/cdev.h> |
||
5 | #include <linux/slab.h> |
||
6 | #include <linux/device.h> |
||
7 | #include <linux/semaphore.h> |
||
8 | f024710b | Tom Mullins | #include <linux/interrupt.h> |
9 | #include <linux/gpio.h> |
||
10 | 2b0ba4bb | Tom Mullins | #include <linux/irq.h> |
11 | 280c6899 | Tom Mullins | #include <asm/atomic.h> |
12 | 83163372 | Tom Mullins | |
13 | MODULE_AUTHOR("Tom Mullins");
|
||
14 | MODULE_LICENSE("GPL");
|
||
15 | |||
16 | #define N_ENCODERS 4 |
||
17 | f024710b | Tom Mullins | const int enc_pins[N_ENCODERS][2] = {{78, 79}, {80, 81}, {82, 83}, {84, 85}}; |
18 | 83163372 | Tom Mullins | struct class *enc_class = NULL; |
19 | |||
20 | 280c6899 | Tom Mullins | struct encoder_device
|
21 | 83163372 | Tom Mullins | { |
22 | struct device *device;
|
||
23 | 280c6899 | Tom Mullins | int pins[2]; |
24 | f024710b | Tom Mullins | int irq[2]; |
25 | 83163372 | Tom Mullins | int status;
|
26 | f024710b | Tom Mullins | atomic_t value; |
27 | 83163372 | Tom Mullins | dev_t dev; |
28 | } |
||
29 | encs[N_ENCODERS]; |
||
30 | |||
31 | 280c6899 | Tom Mullins | static ssize_t enc_show(struct device *dev, struct device_attribute *attr, |
32 | char *buf);
|
||
33 | static ssize_t enc_store(struct device *dev, struct device_attribute *attr, |
||
34 | const char *buf, size_t count); |
||
35 | static void enc_free(struct encoder_device *enc); |
||
36 | static int enc_init(dev_t dev, struct encoder_device *enc, const int *pins); |
||
37 | 83163372 | Tom Mullins | |
38 | 280c6899 | Tom Mullins | DEVICE_ATTR(ticks, S_IWUSR | S_IRUGO, enc_show, enc_store); |
39 | 83163372 | Tom Mullins | |
40 | 280c6899 | Tom Mullins | static ssize_t enc_show(struct device *dev, struct device_attribute *attr, |
41 | char *buf)
|
||
42 | 83163372 | Tom Mullins | { |
43 | 280c6899 | Tom Mullins | size_t nwritten; |
44 | struct encoder_device *enc = dev_get_drvdata(dev);
|
||
45 | nwritten = scnprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&enc->value));
|
||
46 | return nwritten;
|
||
47 | 83163372 | Tom Mullins | } |
48 | |||
49 | 280c6899 | Tom Mullins | static ssize_t enc_store(struct device *dev, struct device_attribute *attr, |
50 | const char *buf, size_t count) |
||
51 | 83163372 | Tom Mullins | { |
52 | char *end;
|
||
53 | 280c6899 | Tom Mullins | struct encoder_device *enc = dev_get_drvdata(dev);
|
54 | atomic_set(&enc->value, simple_strtol(buf, &end, 10));
|
||
55 | 83163372 | Tom Mullins | return count;
|
56 | } |
||
57 | |||
58 | 280c6899 | Tom Mullins | irqreturn_t intA(int irq, void *encp) { |
59 | struct encoder_device *enc = encp;
|
||
60 | f024710b | Tom Mullins | int this = gpio_get_value(enc->pins[0]); |
61 | int other = gpio_get_value(enc->pins[1]); |
||
62 | if (this == other) {
|
||
63 | atomic_inc(&enc->value); |
||
64 | } else {
|
||
65 | atomic_dec(&enc->value); |
||
66 | } |
||
67 | return IRQ_HANDLED;
|
||
68 | } |
||
69 | |||
70 | 280c6899 | Tom Mullins | irqreturn_t intB(int irq, void *encp) { |
71 | struct encoder_device *enc = encp;
|
||
72 | f024710b | Tom Mullins | int this = gpio_get_value(enc->pins[1]); |
73 | int other = gpio_get_value(enc->pins[0]); |
||
74 | if (this == other) {
|
||
75 | atomic_dec(&enc->value); |
||
76 | } else {
|
||
77 | atomic_inc(&enc->value); |
||
78 | } |
||
79 | return IRQ_HANDLED;
|
||
80 | } |
||
81 | |||
82 | 280c6899 | Tom Mullins | static int enc_init(dev_t dev, struct encoder_device *enc, const int *pins) |
83 | 83163372 | Tom Mullins | { |
84 | 280c6899 | Tom Mullins | int i, err;
|
85 | 83163372 | Tom Mullins | |
86 | // initialize members
|
||
87 | enc->dev = dev; |
||
88 | enc->status = 0;
|
||
89 | |||
90 | f024710b | Tom Mullins | // register gpio and interrupts
|
91 | for (i = 0; i < 2; i++) { |
||
92 | |||
93 | enc->pins[i] = pins[i]; |
||
94 | |||
95 | enc->irq[i] = gpio_to_irq(pins[i]); |
||
96 | if (enc->irq[i] < 0) { |
||
97 | printk("Error %d requesting irq number for gpio %d\n", enc->irq[i],
|
||
98 | enc->pins[i]); |
||
99 | return 1; |
||
100 | } |
||
101 | |||
102 | err = gpio_direction_input(enc->pins[i]); |
||
103 | if (err < 0) { |
||
104 | printk("Error %d setting gpio %d to input\n", err, enc->pins[i]);
|
||
105 | return 1; |
||
106 | } |
||
107 | |||
108 | 280c6899 | Tom Mullins | err = request_irq(enc->irq[i], i? intB:intA, 0, "encoder", enc); |
109 | f024710b | Tom Mullins | if (err < 0) { |
110 | printk("Error %d requesting irq %d\n", err, enc->irq[i]);
|
||
111 | return 1; |
||
112 | } |
||
113 | |||
114 | f58d377f | Tom Mullins | err = irq_set_irq_type(enc->irq[i], IRQ_TYPE_EDGE_BOTH); |
115 | if (err < 0) { |
||
116 | printk("Error %d setting irq %d type\n", err, enc->irq[i]);
|
||
117 | return 1; |
||
118 | } |
||
119 | |||
120 | f024710b | Tom Mullins | // TODO the error checking here does not properly clean up after itself
|
121 | // TODO perhaps we should use gpio_request? probably not necessary...
|
||
122 | } |
||
123 | enc->status = 2;
|
||
124 | |||
125 | return 0; |
||
126 | } |
||
127 | |||
128 | 280c6899 | Tom Mullins | int enc_create_dev(struct encoder_device *enc) { |
129 | int err;
|
||
130 | f024710b | Tom Mullins | |
131 | 83163372 | Tom Mullins | // make file in /dev
|
132 | 280c6899 | Tom Mullins | enc->device = device_create(enc_class, NULL, enc->dev, enc, "enc%d", |
133 | 83163372 | Tom Mullins | MINOR(enc->dev)); |
134 | if (IS_ERR(enc->device))
|
||
135 | { |
||
136 | err = PTR_ERR(enc->device); |
||
137 | enc->device = NULL;
|
||
138 | enc_free(enc); |
||
139 | return err;
|
||
140 | } |
||
141 | f024710b | Tom Mullins | enc->status = 3;
|
142 | 83163372 | Tom Mullins | |
143 | 280c6899 | Tom Mullins | device_create_file(enc->device, &dev_attr_ticks); |
144 | // TODO error check
|
||
145 | enc->status = 4;
|
||
146 | |||
147 | 83163372 | Tom Mullins | return 0; |
148 | } |
||
149 | |||
150 | 280c6899 | Tom Mullins | static void enc_free(struct encoder_device *enc) |
151 | 83163372 | Tom Mullins | { |
152 | switch (enc->status)
|
||
153 | { |
||
154 | 280c6899 | Tom Mullins | case 4: |
155 | device_remove_file(enc->device, &dev_attr_ticks); |
||
156 | f024710b | Tom Mullins | case 3: |
157 | 83163372 | Tom Mullins | device_destroy(enc_class, enc->dev); |
158 | enc->device = NULL;
|
||
159 | f024710b | Tom Mullins | case 2: |
160 | free_irq(enc->irq[0], enc);
|
||
161 | free_irq(enc->irq[1], enc);
|
||
162 | 83163372 | Tom Mullins | } |
163 | enc->status = 0;
|
||
164 | } |
||
165 | |||
166 | static void enc_exit_module(void) |
||
167 | { |
||
168 | int i;
|
||
169 | for (i = 0; i < N_ENCODERS; i++) |
||
170 | { |
||
171 | enc_free(&encs[i]); |
||
172 | } |
||
173 | if (enc_class) {
|
||
174 | class_destroy(enc_class); |
||
175 | enc_class = NULL;
|
||
176 | } |
||
177 | } |
||
178 | module_exit(enc_exit_module); |
||
179 | |||
180 | static int __init enc_init_module(void) |
||
181 | { |
||
182 | int i, err;
|
||
183 | |||
184 | f024710b | Tom Mullins | // initialize enc structures
|
185 | for (i = 0; i < N_ENCODERS; i++) { |
||
186 | 280c6899 | Tom Mullins | err = enc_init(MKDEV(0, i), &encs[i], enc_pins[i]);
|
187 | f024710b | Tom Mullins | if (err)
|
188 | { |
||
189 | printk(KERN_WARNING "Error %d initializing encoder %d\n", err, i);
|
||
190 | enc_exit_module(); |
||
191 | 280c6899 | Tom Mullins | return err;
|
192 | f024710b | Tom Mullins | } |
193 | } |
||
194 | |||
195 | 83163372 | Tom Mullins | // register our device class for files in /dev
|
196 | enc_class = class_create(THIS_MODULE, "encoder");
|
||
197 | if (IS_ERR(enc_class))
|
||
198 | { |
||
199 | err = PTR_ERR(enc_class); |
||
200 | enc_class = NULL;
|
||
201 | printk(KERN_WARNING "Error %d creating device class\n", err);
|
||
202 | } |
||
203 | else
|
||
204 | { |
||
205 | f024710b | Tom Mullins | // create each device
|
206 | 83163372 | Tom Mullins | for (i = 0; i < N_ENCODERS; i++) { |
207 | f024710b | Tom Mullins | err = enc_create_dev(&encs[i]); |
208 | 83163372 | Tom Mullins | if (err)
|
209 | { |
||
210 | f024710b | Tom Mullins | printk(KERN_WARNING "Error %d creating enc%d\n", err, i);
|
211 | 83163372 | Tom Mullins | enc_exit_module(); |
212 | 280c6899 | Tom Mullins | return err;
|
213 | 83163372 | Tom Mullins | } |
214 | } |
||
215 | } |
||
216 | |||
217 | return 0; |
||
218 | } |
||
219 | module_init(enc_init_module); |