Project

General

Profile

Statistics
| Branch: | Revision:

scoutos / scout_gumstix / encoder / encoder.c @ 280c6899

History | View | Annotate | Download (4.95 KB)

1
#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
#include <linux/interrupt.h>
9
#include <linux/gpio.h>
10
#include <asm/atomic.h>
11

    
12
MODULE_AUTHOR("Tom Mullins");
13
MODULE_LICENSE("GPL");
14

    
15
#define N_ENCODERS 4
16
const int enc_pins[N_ENCODERS][2] = {{78, 79}, {80, 81}, {82, 83}, {84, 85}};
17
struct class *enc_class = NULL;
18

    
19
struct encoder_device
20
{
21
  struct device *device;
22
  int pins[2];
23
  int irq[2];
24
  int status;
25
  atomic_t value;
26
  dev_t dev;
27
}
28
encs[N_ENCODERS];
29

    
30
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

    
37
DEVICE_ATTR(ticks, S_IWUSR | S_IRUGO, enc_show, enc_store);
38

    
39
static ssize_t enc_show(struct device *dev, struct device_attribute *attr,
40
    char *buf)
41
{
42
  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
}
47

    
48
static ssize_t enc_store(struct device *dev, struct device_attribute *attr,
49
    const char *buf, size_t count)
50
{
51
  char *end;
52
  struct encoder_device *enc = dev_get_drvdata(dev);
53
  atomic_set(&enc->value, simple_strtol(buf, &end, 10));
54
  return count;
55
}
56

    
57
irqreturn_t intA(int irq, void *encp) {
58
  struct encoder_device *enc = encp;
59
  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
irqreturn_t intB(int irq, void *encp) {
70
  struct encoder_device *enc = encp;
71
  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
static int enc_init(dev_t dev, struct encoder_device *enc, const int *pins)
82
{
83
  int i, err;
84

    
85
  // initialize members
86
  enc->dev = dev;
87
  enc->status = 0;
88

    
89
  // 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
    err = request_irq(enc->irq[i], i? intB:intA, 0, "encoder", enc);
108
    if (err < 0) {
109
      printk("Error %d requesting irq %d\n", err, enc->irq[i]);
110
      return 1;
111
    }
112

    
113
    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
    // 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
int enc_create_dev(struct encoder_device *enc) {
128
  int err;
129

    
130
  // make file in /dev
131
  enc->device = device_create(enc_class, NULL, enc->dev, enc, "enc%d",
132
      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
  enc->status = 3;
141

    
142
  device_create_file(enc->device, &dev_attr_ticks);
143
  // TODO error check
144
  enc->status = 4;
145

    
146
  return 0;
147
}
148

    
149
static void enc_free(struct encoder_device *enc)
150
{
151
  switch (enc->status)
152
  {
153
    case 4:
154
      device_remove_file(enc->device, &dev_attr_ticks);
155
    case 3:
156
      device_destroy(enc_class, enc->dev);
157
      enc->device = NULL;
158
    case 2:
159
      free_irq(enc->irq[0], enc);
160
      free_irq(enc->irq[1], enc);
161
  }
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
  // initialize enc structures
184
  for (i = 0; i < N_ENCODERS; i++) {
185
    err = enc_init(MKDEV(0, i), &encs[i], enc_pins[i]);
186
    if (err)
187
    {
188
      printk(KERN_WARNING "Error %d initializing encoder %d\n", err, i);
189
      enc_exit_module();
190
      return err;
191
    }
192
  }
193

    
194
  // 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
    // create each device
205
    for (i = 0; i < N_ENCODERS; i++) {
206
      err = enc_create_dev(&encs[i]);
207
      if (err)
208
      {
209
        printk(KERN_WARNING "Error %d creating enc%d\n", err, i);
210
        enc_exit_module();
211
        return err;
212
      }
213
    }
214
  }
215

    
216
  return 0;
217
}
218
module_init(enc_init_module);