Project

General

Profile

Statistics
| Branch: | Revision:

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);