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