blob: a91006ecaeb1a97c37ae7c94febe6e7ea1fe27c8 [file] [log] [blame]
Austin Schuh0aaebf32022-02-24 14:22:10 -08001/*
2 * adis16505.c - Driver for the adis16505 IMU used by 971.
3 */
4#include <linux/cdev.h>
5#include <linux/debugfs.h>
6#include <linux/delay.h>
7#include <linux/interrupt.h>
8#include <linux/kernel.h> /* Needed for pr_info() */
9#include <linux/kfifo.h>
10#include <linux/module.h> /* Needed by all modules */
11#include <linux/poll.h>
12
13#include <linux/of_gpio.h>
14#include <linux/spi/spi.h>
15#include <linux/of_address.h>
16#include <linux/of.h>
17#include <linux/of_platform.h>
18
19
20MODULE_LICENSE("GPL");
21MODULE_AUTHOR("frc971");
22MODULE_DESCRIPTION("adis16505 rp2040 driver");
23
24#define MODULE_NAME "adis16505"
25
26//! filter for the device tree class
27static struct of_device_id adis16505_match[] = {
28 {.compatible = "frc971,adis16505"}, {}};
29
30MODULE_DEVICE_TABLE(of, adis16505_match);
31
32#define TRANSFER_SIZE 42
33struct imu_sample {
34 char time[8];
35 char d[TRANSFER_SIZE];
36};
37
38struct adis16505_state {
39 dev_t character_device;
40 struct class *device_class;
41 struct cdev handle_cdev;
42
43 struct spi_device *spi;
44
45 struct spi_message spi_msg;
46
47 struct spi_transfer spi_xfer;
48
49 char tx_buff[128];
50 char rx_buff[128];
51
52 int count;
53
54 spinlock_t lock;
55
56 wait_queue_head_t wq;
57
58 spinlock_t fifo_read_lock;
59 DECLARE_KFIFO(fifo, struct imu_sample, 32);
60};
61
62static int adis16505_dev_open(struct inode *in, struct file *f) {
63 struct adis16505_state *ts =
64 container_of(in->i_cdev, struct adis16505_state, handle_cdev);
65 int count;
66
67 f->private_data = ts;
68
69 spin_lock(&ts->lock);
70 count = ts->count;
71 if (count == 0) {
72 ++(ts->count);
73 }
74 spin_unlock(&ts->lock);
75
76 printk("open %p, count %d\n", ts, count);
77 if (count > 0) {
78 return -EBUSY;
79 }
80 return 0;
81}
82
83static int adis16505_dev_release(struct inode *in, struct file *f) {
84 struct adis16505_state *ts;
85 ts = container_of(in->i_cdev, struct adis16505_state, handle_cdev);
86
87 printk("release %p\n", ts);
88 spin_lock(&ts->lock);
89 --(ts->count);
90 spin_unlock(&ts->lock);
91
92 return 0;
93}
94
95static ssize_t adis16505_dev_read(struct file *f, char *d, size_t s,
96 loff_t *of) {
97 struct adis16505_state *ts = f->private_data;
98 int err;
99
100 if (s != sizeof(struct imu_sample)) {
101 return -EINVAL;
102 }
103
104 while (true) {
105 struct imu_sample sample;
106 int elements;
107
108 spin_lock(&ts->fifo_read_lock);
109 elements = kfifo_get(&ts->fifo, &sample);
110 spin_unlock(&ts->fifo_read_lock);
111
112 if (elements == 0) {
113 bool empty;
114 if (f->f_flags & O_NONBLOCK) {
115 return -EAGAIN;
116 }
117
118 err = wait_event_interruptible(ts->wq,
119 (spin_lock(&ts->fifo_read_lock),
120 empty = !kfifo_is_empty(&ts->fifo),
121 spin_unlock(&ts->fifo_read_lock), empty));
122 if (err != 0) {
123 return err;
124 }
125 continue;
126 }
127
128 memcpy(d, &sample, sizeof(sample));
129 return sizeof(sample);
130 }
131}
132
133static unsigned int adis16505_dev_poll(struct file *f,
134 struct poll_table_struct *wait) {
135 struct adis16505_state *ts = f->private_data;
136 __poll_t mask = 0;
137
138 poll_wait(f, &ts->wq, wait);
139
140 spin_lock(&ts->fifo_read_lock);
141 if (!kfifo_is_empty(&ts->fifo)) {
142 mask |= (POLLIN | POLLRDNORM);
143 }
144 spin_unlock(&ts->fifo_read_lock);
145
146 return mask;
147}
148
149static const struct file_operations adis16505_cdev_opps = {
150 .read = adis16505_dev_read,
151 .open = adis16505_dev_open,
152 .release = adis16505_dev_release,
153 .poll = adis16505_dev_poll,
154};
155
156static void all_done(void *ts_ptr) {
157 // struct adis16505_state *ts = ts_ptr;
158 // printk("All done %x %x\n", ts->rx_buff[0], ts->rx_buff[1]);
159}
160
161static irqreturn_t adis16505_irq(int irq, void *handle) {
162 struct adis16505_state *ts = handle;
163 struct imu_sample s;
164 int err;
165 int i;
166
167 u64 time = ktime_get_ns();
168 memcpy(&s.time, &time, sizeof(time));
169
170 spi_message_init(&ts->spi_msg);
171 for (i = 0; i < TRANSFER_SIZE; ++i) {
172 ts->tx_buff[i] = i;
173 }
174
175 ts->spi_xfer.tx_buf = ts->tx_buff;
176 ts->spi_xfer.rx_buf = ts->rx_buff;
177 ts->spi_xfer.len = TRANSFER_SIZE;
178
179 spi_message_add_tail(&ts->spi_xfer, &ts->spi_msg);
180
181 ts->spi_msg.complete = all_done;
182 ts->spi_msg.context = ts;
183
184 err = spi_sync(ts->spi, &ts->spi_msg);
185
186 // TODO(austin): Timestamp. Also decode the packet for real.
187 for (i = 0; i < TRANSFER_SIZE; ++i) {
188 s.d[i] = ts->rx_buff[i];
189 }
190
191 // Attempt to emplace. If it fails, just drop the data.
192 kfifo_put(&ts->fifo, s);
193
194 wake_up_interruptible(&ts->wq);
195
196 return IRQ_HANDLED;
197}
198
199static int adis16505_probe(struct spi_device *spi) {
200 int err;
201 struct adis16505_state *ts;
202
203 if (!spi->irq) {
204 dev_dbg(&spi->dev, "no IRQ?\n");
205 return -EINVAL;
206 }
207
208 if (spi->max_speed_hz > 10000000) {
209 dev_err(&spi->dev, "f(sample) %d KHz?\n", spi->max_speed_hz / 1000);
210 return -EINVAL;
211 }
212
213 spi->bits_per_word = 8;
214 spi->mode = SPI_MODE_3;
215 spi->max_speed_hz = 2000000;
216
217 err = spi_setup(spi);
218 if (err < 0) {
219 return err;
220 }
221
222 ts = kzalloc(sizeof(struct adis16505_state), GFP_KERNEL);
223
224 if (!ts) {
225 err = -ENOMEM;
226 goto err_free_mem;
227 }
228
229 printk("Ts allocated %p\n", ts);
230
231 spin_lock_init(&ts->lock);
232 spin_lock_init(&ts->fifo_read_lock);
233 ts->count = 0;
234 INIT_KFIFO(ts->fifo);
235 init_waitqueue_head(&ts->wq);
236
237 spi_set_drvdata(spi, ts);
238 ts->spi = spi;
239
240 // Flags are sourced from the device tree.
241 err = request_threaded_irq(spi->irq, NULL, adis16505_irq, IRQF_ONESHOT,
242 spi->dev.driver->name, ts);
243
244 if (!ts) {
245 dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
246 goto err_free_mem;
247 }
248
249 err = alloc_chrdev_region(&ts->character_device, 0, 1, "adis16505");
250 if (err < 0) {
251 dev_dbg(&spi->dev, "alloc_chrdev_region error %i", err);
252 goto err_free_irq;
253 }
254
255 // create device class
256 if ((ts->device_class = class_create(THIS_MODULE, "adis16505_class")) ==
257 NULL) {
258 dev_dbg(&spi->dev, "class_create error");
259 goto error_classCreate;
260 }
261
262 if (NULL == device_create(ts->device_class, NULL, ts->character_device, NULL,
263 "adis16505")) {
264 dev_dbg(&spi->dev, "device_create error");
265 goto error_deviceCreate;
266 }
267
268 cdev_init(&ts->handle_cdev, &adis16505_cdev_opps);
269 err = cdev_add(&ts->handle_cdev, ts->character_device, 1);
270 if (-1 == err) {
271 dev_dbg(&spi->dev, "cdev_add error %i", err);
272 goto error_device_add;
273 return -1;
274 }
275
276 dev_dbg(&spi->dev, "Probed adis16505\n");
277
278 if (err < 0) {
279 goto err_free_mem;
280 }
281
282 return 0;
283
284error_device_add:
285 device_destroy(ts->device_class, ts->character_device);
286error_deviceCreate:
287 class_destroy(ts->device_class);
288error_classCreate:
289 unregister_chrdev_region(ts->character_device, 1);
290err_free_irq:
291 free_irq(spi->irq, ts);
292
293err_free_mem:
294 kfree(ts);
295 return err;
296}
297
298static int adis16505_remove(struct spi_device *spi) {
299 struct adis16505_state *ts = spi_get_drvdata(spi);
300
301 device_destroy(ts->device_class, ts->character_device);
302
303 class_destroy(ts->device_class);
304
305 unregister_chrdev_region(ts->character_device, 1);
306
307 free_irq(spi->irq, ts);
308
309 kfree(ts);
310
311 dev_dbg(&spi->dev, "unregistered adis16505\n");
312 return 0;
313}
314
315static struct spi_driver adis16505_driver = {
316 .driver =
317 {
318 .name = "adis16505",
319 .of_match_table = of_match_ptr(adis16505_match),
320 },
321 .probe = adis16505_probe,
322 .remove = adis16505_remove,
323};
324
325module_spi_driver(adis16505_driver);