blob: f0eb6ae7c918593871ac5ae666d734909832d863 [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 */
Austin Schuh0aaebf32022-02-24 14:22:10 -080011#include <linux/of.h>
Philipp Schrader790cb542023-07-05 21:06:52 -070012#include <linux/of_address.h>
13#include <linux/of_gpio.h>
Austin Schuh0aaebf32022-02-24 14:22:10 -080014#include <linux/of_platform.h>
Philipp Schrader790cb542023-07-05 21:06:52 -070015#include <linux/poll.h>
16#include <linux/spi/spi.h>
Austin Schuh0aaebf32022-02-24 14:22:10 -080017
18MODULE_LICENSE("GPL");
19MODULE_AUTHOR("frc971");
20MODULE_DESCRIPTION("adis16505 rp2040 driver");
21
22#define MODULE_NAME "adis16505"
23
24//! filter for the device tree class
25static struct of_device_id adis16505_match[] = {
26 {.compatible = "frc971,adis16505"}, {}};
27
28MODULE_DEVICE_TABLE(of, adis16505_match);
29
30#define TRANSFER_SIZE 42
31struct imu_sample {
32 char time[8];
33 char d[TRANSFER_SIZE];
34};
35
36struct adis16505_state {
37 dev_t character_device;
38 struct class *device_class;
39 struct cdev handle_cdev;
40
41 struct spi_device *spi;
42
43 struct spi_message spi_msg;
44
45 struct spi_transfer spi_xfer;
46
47 char tx_buff[128];
48 char rx_buff[128];
49
Austin Schuh6283b262022-12-31 23:11:15 -080050 atomic_t count;
Austin Schuh0aaebf32022-02-24 14:22:10 -080051
52 spinlock_t lock;
53
54 wait_queue_head_t wq;
55
56 spinlock_t fifo_read_lock;
57 DECLARE_KFIFO(fifo, struct imu_sample, 32);
58};
59
60static int adis16505_dev_open(struct inode *in, struct file *f) {
61 struct adis16505_state *ts =
62 container_of(in->i_cdev, struct adis16505_state, handle_cdev);
Austin Schuh6283b262022-12-31 23:11:15 -080063 int count = 0;
Austin Schuh0aaebf32022-02-24 14:22:10 -080064
65 f->private_data = ts;
Austin Schuh6283b262022-12-31 23:11:15 -080066 count = atomic_cmpxchg(&ts->count, 0, 1);
Austin Schuh0aaebf32022-02-24 14:22:10 -080067
Austin Schuh0aaebf32022-02-24 14:22:10 -080068 if (count > 0) {
69 return -EBUSY;
70 }
Austin Schuh6283b262022-12-31 23:11:15 -080071
72 // Enable the IRQ after we've declared the device open.
73 enable_irq(ts->spi->irq);
74
Austin Schuh0aaebf32022-02-24 14:22:10 -080075 return 0;
76}
77
78static int adis16505_dev_release(struct inode *in, struct file *f) {
79 struct adis16505_state *ts;
80 ts = container_of(in->i_cdev, struct adis16505_state, handle_cdev);
81
Austin Schuh6283b262022-12-31 23:11:15 -080082 // Disable before declaring ourselves closed so we don't fire the IRQ when we
83 // are disabled, or let someone else open it up again before we disable it.
84 disable_irq(ts->spi->irq);
85
86 if (atomic_cmpxchg(&ts->count, 1, 0) != 1) {
87 BUG_ON(true);
88 }
Austin Schuh0aaebf32022-02-24 14:22:10 -080089
90 return 0;
91}
92
93static ssize_t adis16505_dev_read(struct file *f, char *d, size_t s,
94 loff_t *of) {
95 struct adis16505_state *ts = f->private_data;
96 int err;
97
98 if (s != sizeof(struct imu_sample)) {
99 return -EINVAL;
100 }
101
102 while (true) {
103 struct imu_sample sample;
104 int elements;
105
106 spin_lock(&ts->fifo_read_lock);
107 elements = kfifo_get(&ts->fifo, &sample);
108 spin_unlock(&ts->fifo_read_lock);
109
110 if (elements == 0) {
111 bool empty;
112 if (f->f_flags & O_NONBLOCK) {
113 return -EAGAIN;
114 }
115
Philipp Schrader790cb542023-07-05 21:06:52 -0700116 err = wait_event_interruptible(
117 ts->wq,
118 (spin_lock(&ts->fifo_read_lock), empty = !kfifo_is_empty(&ts->fifo),
119 spin_unlock(&ts->fifo_read_lock), empty));
Austin Schuh0aaebf32022-02-24 14:22:10 -0800120 if (err != 0) {
121 return err;
122 }
123 continue;
124 }
125
126 memcpy(d, &sample, sizeof(sample));
127 return sizeof(sample);
128 }
129}
130
131static unsigned int adis16505_dev_poll(struct file *f,
132 struct poll_table_struct *wait) {
133 struct adis16505_state *ts = f->private_data;
134 __poll_t mask = 0;
135
136 poll_wait(f, &ts->wq, wait);
137
138 spin_lock(&ts->fifo_read_lock);
139 if (!kfifo_is_empty(&ts->fifo)) {
140 mask |= (POLLIN | POLLRDNORM);
141 }
142 spin_unlock(&ts->fifo_read_lock);
143
144 return mask;
145}
146
147static const struct file_operations adis16505_cdev_opps = {
148 .read = adis16505_dev_read,
149 .open = adis16505_dev_open,
150 .release = adis16505_dev_release,
151 .poll = adis16505_dev_poll,
152};
153
154static void all_done(void *ts_ptr) {
155 // struct adis16505_state *ts = ts_ptr;
156 // printk("All done %x %x\n", ts->rx_buff[0], ts->rx_buff[1]);
157}
158
159static irqreturn_t adis16505_irq(int irq, void *handle) {
160 struct adis16505_state *ts = handle;
161 struct imu_sample s;
162 int err;
163 int i;
164
165 u64 time = ktime_get_ns();
166 memcpy(&s.time, &time, sizeof(time));
167
168 spi_message_init(&ts->spi_msg);
169 for (i = 0; i < TRANSFER_SIZE; ++i) {
170 ts->tx_buff[i] = i;
171 }
172
173 ts->spi_xfer.tx_buf = ts->tx_buff;
174 ts->spi_xfer.rx_buf = ts->rx_buff;
175 ts->spi_xfer.len = TRANSFER_SIZE;
176
177 spi_message_add_tail(&ts->spi_xfer, &ts->spi_msg);
178
179 ts->spi_msg.complete = all_done;
180 ts->spi_msg.context = ts;
181
182 err = spi_sync(ts->spi, &ts->spi_msg);
183
184 // TODO(austin): Timestamp. Also decode the packet for real.
185 for (i = 0; i < TRANSFER_SIZE; ++i) {
186 s.d[i] = ts->rx_buff[i];
187 }
188
189 // Attempt to emplace. If it fails, just drop the data.
190 kfifo_put(&ts->fifo, s);
191
192 wake_up_interruptible(&ts->wq);
193
194 return IRQ_HANDLED;
195}
196
197static int adis16505_probe(struct spi_device *spi) {
198 int err;
199 struct adis16505_state *ts;
200
201 if (!spi->irq) {
202 dev_dbg(&spi->dev, "no IRQ?\n");
203 return -EINVAL;
204 }
205
206 if (spi->max_speed_hz > 10000000) {
207 dev_err(&spi->dev, "f(sample) %d KHz?\n", spi->max_speed_hz / 1000);
208 return -EINVAL;
209 }
210
211 spi->bits_per_word = 8;
212 spi->mode = SPI_MODE_3;
213 spi->max_speed_hz = 2000000;
214
215 err = spi_setup(spi);
216 if (err < 0) {
217 return err;
218 }
219
220 ts = kzalloc(sizeof(struct adis16505_state), GFP_KERNEL);
221
222 if (!ts) {
223 err = -ENOMEM;
224 goto err_free_mem;
225 }
226
227 printk("Ts allocated %p\n", ts);
228
229 spin_lock_init(&ts->lock);
230 spin_lock_init(&ts->fifo_read_lock);
Austin Schuh6283b262022-12-31 23:11:15 -0800231 atomic_set(&ts->count, 0);
Austin Schuh0aaebf32022-02-24 14:22:10 -0800232 INIT_KFIFO(ts->fifo);
233 init_waitqueue_head(&ts->wq);
234
235 spi_set_drvdata(spi, ts);
236 ts->spi = spi;
237
238 // Flags are sourced from the device tree.
239 err = request_threaded_irq(spi->irq, NULL, adis16505_irq, IRQF_ONESHOT,
240 spi->dev.driver->name, ts);
241
Austin Schuh6283b262022-12-31 23:11:15 -0800242 if (err < 0) {
Austin Schuh0aaebf32022-02-24 14:22:10 -0800243 dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
244 goto err_free_mem;
245 }
246
Austin Schuh6283b262022-12-31 23:11:15 -0800247 // Immediately disable the IRQ. Opening the device will enable it, so this
248 // lets us leave the driver probed all the time and only use it when userspace
249 // asks.
250 //
251 // Note: the IRQ will fire probably once before we get it disabled... It
252 // might initiate a transfer from a device which isn't connected, which should
253 // just return 0 for everything. This isn't actually a huge concern.
254 disable_irq(spi->irq);
255
Austin Schuh0aaebf32022-02-24 14:22:10 -0800256 err = alloc_chrdev_region(&ts->character_device, 0, 1, "adis16505");
257 if (err < 0) {
258 dev_dbg(&spi->dev, "alloc_chrdev_region error %i", err);
259 goto err_free_irq;
260 }
261
262 // create device class
263 if ((ts->device_class = class_create(THIS_MODULE, "adis16505_class")) ==
264 NULL) {
265 dev_dbg(&spi->dev, "class_create error");
266 goto error_classCreate;
267 }
268
269 if (NULL == device_create(ts->device_class, NULL, ts->character_device, NULL,
270 "adis16505")) {
271 dev_dbg(&spi->dev, "device_create error");
272 goto error_deviceCreate;
273 }
274
275 cdev_init(&ts->handle_cdev, &adis16505_cdev_opps);
276 err = cdev_add(&ts->handle_cdev, ts->character_device, 1);
277 if (-1 == err) {
278 dev_dbg(&spi->dev, "cdev_add error %i", err);
279 goto error_device_add;
280 return -1;
281 }
282
283 dev_dbg(&spi->dev, "Probed adis16505\n");
284
285 if (err < 0) {
286 goto err_free_mem;
287 }
288
289 return 0;
290
291error_device_add:
292 device_destroy(ts->device_class, ts->character_device);
293error_deviceCreate:
294 class_destroy(ts->device_class);
295error_classCreate:
296 unregister_chrdev_region(ts->character_device, 1);
297err_free_irq:
298 free_irq(spi->irq, ts);
299
300err_free_mem:
301 kfree(ts);
302 return err;
303}
304
Austin Schuh6283b262022-12-31 23:11:15 -0800305static void adis16505_remove(struct spi_device *spi) {
Austin Schuh0aaebf32022-02-24 14:22:10 -0800306 struct adis16505_state *ts = spi_get_drvdata(spi);
307
308 device_destroy(ts->device_class, ts->character_device);
309
310 class_destroy(ts->device_class);
311
312 unregister_chrdev_region(ts->character_device, 1);
313
314 free_irq(spi->irq, ts);
315
316 kfree(ts);
317
318 dev_dbg(&spi->dev, "unregistered adis16505\n");
Austin Schuh0aaebf32022-02-24 14:22:10 -0800319}
320
321static struct spi_driver adis16505_driver = {
322 .driver =
323 {
324 .name = "adis16505",
325 .of_match_table = of_match_ptr(adis16505_match),
326 },
327 .probe = adis16505_probe,
328 .remove = adis16505_remove,
329};
330
Philipp Schrader790cb542023-07-05 21:06:52 -0700331module_spi_driver(adis16505_driver);