Project

General

Profile

Statistics
| Branch: | Revision:

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