brcm2708: update to latest patches from RPi foundation
[openwrt/openwrt.git] / target / linux / brcm2708 / patches-4.19 / 950-0078-Support-for-Blokas-Labs-pisound-board.patch
1 From 85ef9efcc598bff1d783620e23c09aed873e7aee Mon Sep 17 00:00:00 2001
2 From: gtrainavicius <gtrainavicius@users.noreply.github.com>
3 Date: Sun, 23 Oct 2016 12:06:53 +0300
4 Subject: [PATCH 078/806] Support for Blokas Labs pisound board
5
6 Pisound dynamic overlay (#1760)
7
8 Restructuring pisound-overlay.dts, so it can be loaded and unloaded dynamically using dtoverlay.
9
10 Print a logline when the kernel module is removed.
11
12 pisound improvements:
13
14 * Added a writable sysfs object to enable scripts / user space software
15 to blink MIDI activity LEDs for variable duration.
16 * Improved hw_param constraints setting.
17 * Added compatibility with S16_LE sample format.
18 * Exposed some simple placeholder volume controls, so the card appears
19 in volumealsa widget.
20
21 Add missing SND_PISOUND selects dependency to SND_RAWMIDI
22
23 Without it the Pisound module fails to compile.
24 See https://github.com/raspberrypi/linux/issues/2366
25
26 Updates for Pisound module code:
27
28 * Merged 'Fix a warning in DEBUG builds' (1c8b82b).
29 * Updating some strings and copyright information.
30 * Fix for handling high load of MIDI input and output.
31 * Use dual rate oversampling ratio for 96kHz instead of single
32 rate one.
33
34 Signed-off-by: Giedrius Trainavicius <giedrius@blokas.io>
35
36 Fixing memset call in pisound.c
37
38 Signed-off-by: Giedrius Trainavicius <giedrius@blokas.io>
39
40 Fix for Pisound's MIDI Input getting blocked for a while in rare cases.
41
42 There was a possible race condition which could lead to Input's FIFO queue
43 to be underflown, causing high amount of processing in the worker thread for
44 some period of time.
45
46 Signed-off-by: Giedrius Trainavicius <giedrius@blokas.io>
47 ---
48 .../devicetree/bindings/vendor-prefixes.txt | 1 +
49 sound/soc/bcm/pisound.c | 1204 +++++++++++++++++
50 2 files changed, 1205 insertions(+)
51 create mode 100644 sound/soc/bcm/pisound.c
52
53 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt
54 +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
55 @@ -56,6 +56,7 @@ axis Axis Communications AB
56 bananapi BIPAI KEJI LIMITED
57 bhf Beckhoff Automation GmbH & Co. KG
58 bitmain Bitmain Technologies
59 +blokaslabs Vilniaus Blokas UAB
60 boe BOE Technology Group Co., Ltd.
61 bosch Bosch Sensortec GmbH
62 boundary Boundary Devices Inc.
63 --- /dev/null
64 +++ b/sound/soc/bcm/pisound.c
65 @@ -0,0 +1,1204 @@
66 +/*
67 + * Pisound Linux kernel module.
68 + * Copyright (C) 2016-2017 Vilniaus Blokas UAB, https://blokas.io/pisound
69 + *
70 + * This program is free software; you can redistribute it and/or
71 + * modify it under the terms of the GNU General Public License
72 + * as published by the Free Software Foundation; version 2 of the
73 + * License.
74 + *
75 + * This program is distributed in the hope that it will be useful,
76 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
77 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
78 + * GNU General Public License for more details.
79 + *
80 + * You should have received a copy of the GNU General Public License
81 + * along with this program; if not, write to the Free Software
82 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
83 + * MA 02110-1301, USA.
84 + */
85 +
86 +#include <linux/init.h>
87 +#include <linux/module.h>
88 +#include <linux/platform_device.h>
89 +#include <linux/gpio.h>
90 +#include <linux/kobject.h>
91 +#include <linux/sysfs.h>
92 +#include <linux/delay.h>
93 +#include <linux/spi/spi.h>
94 +#include <linux/interrupt.h>
95 +#include <linux/kfifo.h>
96 +#include <linux/jiffies.h>
97 +
98 +#include <sound/core.h>
99 +#include <sound/pcm.h>
100 +#include <sound/pcm_params.h>
101 +#include <sound/soc.h>
102 +#include <sound/jack.h>
103 +#include <sound/rawmidi.h>
104 +#include <sound/asequencer.h>
105 +#include <sound/control.h>
106 +
107 +static int pisnd_spi_init(struct device *dev);
108 +static void pisnd_spi_uninit(void);
109 +
110 +static void pisnd_spi_flush(void);
111 +static void pisnd_spi_start(void);
112 +static uint8_t pisnd_spi_recv(uint8_t *buffer, uint8_t length);
113 +
114 +typedef void (*pisnd_spi_recv_cb)(void *data);
115 +static void pisnd_spi_set_callback(pisnd_spi_recv_cb cb, void *data);
116 +
117 +static const char *pisnd_spi_get_serial(void);
118 +static const char *pisnd_spi_get_id(void);
119 +static const char *pisnd_spi_get_version(void);
120 +
121 +static int pisnd_midi_init(struct snd_card *card);
122 +static void pisnd_midi_uninit(void);
123 +
124 +enum task_e {
125 + TASK_PROCESS = 0,
126 +};
127 +
128 +static void pisnd_schedule_process(enum task_e task);
129 +
130 +#define PISOUND_LOG_PREFIX "pisound: "
131 +
132 +#ifdef PISOUND_DEBUG
133 +# define printd(...) pr_alert(PISOUND_LOG_PREFIX __VA_ARGS__)
134 +#else
135 +# define printd(...) do {} while (0)
136 +#endif
137 +
138 +#define printe(...) pr_err(PISOUND_LOG_PREFIX __VA_ARGS__)
139 +#define printi(...) pr_info(PISOUND_LOG_PREFIX __VA_ARGS__)
140 +
141 +static struct snd_rawmidi *g_rmidi;
142 +static struct snd_rawmidi_substream *g_midi_output_substream;
143 +
144 +static int pisnd_output_open(struct snd_rawmidi_substream *substream)
145 +{
146 + g_midi_output_substream = substream;
147 + return 0;
148 +}
149 +
150 +static int pisnd_output_close(struct snd_rawmidi_substream *substream)
151 +{
152 + g_midi_output_substream = NULL;
153 + return 0;
154 +}
155 +
156 +static void pisnd_output_trigger(
157 + struct snd_rawmidi_substream *substream,
158 + int up
159 + )
160 +{
161 + if (substream != g_midi_output_substream) {
162 + printe("MIDI output trigger called for an unexpected stream!");
163 + return;
164 + }
165 +
166 + if (!up)
167 + return;
168 +
169 + pisnd_spi_start();
170 +}
171 +
172 +static void pisnd_output_drain(struct snd_rawmidi_substream *substream)
173 +{
174 + pisnd_spi_flush();
175 +}
176 +
177 +static int pisnd_input_open(struct snd_rawmidi_substream *substream)
178 +{
179 + return 0;
180 +}
181 +
182 +static int pisnd_input_close(struct snd_rawmidi_substream *substream)
183 +{
184 + return 0;
185 +}
186 +
187 +static void pisnd_midi_recv_callback(void *substream)
188 +{
189 + uint8_t data[128];
190 + uint8_t n = 0;
191 +
192 + while ((n = pisnd_spi_recv(data, sizeof(data)))) {
193 + int res = snd_rawmidi_receive(substream, data, n);
194 + (void)res;
195 + printd("midi recv %u bytes, res = %d\n", n, res);
196 + }
197 +}
198 +
199 +static void pisnd_input_trigger(struct snd_rawmidi_substream *substream, int up)
200 +{
201 + if (up) {
202 + pisnd_spi_set_callback(pisnd_midi_recv_callback, substream);
203 + pisnd_schedule_process(TASK_PROCESS);
204 + } else {
205 + pisnd_spi_set_callback(NULL, NULL);
206 + }
207 +}
208 +
209 +static struct snd_rawmidi_ops pisnd_output_ops = {
210 + .open = pisnd_output_open,
211 + .close = pisnd_output_close,
212 + .trigger = pisnd_output_trigger,
213 + .drain = pisnd_output_drain,
214 +};
215 +
216 +static struct snd_rawmidi_ops pisnd_input_ops = {
217 + .open = pisnd_input_open,
218 + .close = pisnd_input_close,
219 + .trigger = pisnd_input_trigger,
220 +};
221 +
222 +static void pisnd_get_port_info(
223 + struct snd_rawmidi *rmidi,
224 + int number,
225 + struct snd_seq_port_info *seq_port_info
226 + )
227 +{
228 + seq_port_info->type =
229 + SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC |
230 + SNDRV_SEQ_PORT_TYPE_HARDWARE |
231 + SNDRV_SEQ_PORT_TYPE_PORT;
232 + seq_port_info->midi_voices = 0;
233 +}
234 +
235 +static struct snd_rawmidi_global_ops pisnd_global_ops = {
236 + .get_port_info = pisnd_get_port_info,
237 +};
238 +
239 +static int pisnd_midi_init(struct snd_card *card)
240 +{
241 + int err;
242 +
243 + g_midi_output_substream = NULL;
244 +
245 + err = snd_rawmidi_new(card, "pisound MIDI", 0, 1, 1, &g_rmidi);
246 +
247 + if (err < 0) {
248 + printe("snd_rawmidi_new failed: %d\n", err);
249 + return err;
250 + }
251 +
252 + strcpy(g_rmidi->name, "pisound MIDI ");
253 + strcat(g_rmidi->name, pisnd_spi_get_serial());
254 +
255 + g_rmidi->info_flags =
256 + SNDRV_RAWMIDI_INFO_OUTPUT |
257 + SNDRV_RAWMIDI_INFO_INPUT |
258 + SNDRV_RAWMIDI_INFO_DUPLEX;
259 +
260 + g_rmidi->ops = &pisnd_global_ops;
261 +
262 + g_rmidi->private_data = (void *)0;
263 +
264 + snd_rawmidi_set_ops(
265 + g_rmidi,
266 + SNDRV_RAWMIDI_STREAM_OUTPUT,
267 + &pisnd_output_ops
268 + );
269 +
270 + snd_rawmidi_set_ops(
271 + g_rmidi,
272 + SNDRV_RAWMIDI_STREAM_INPUT,
273 + &pisnd_input_ops
274 + );
275 +
276 + return 0;
277 +}
278 +
279 +static void pisnd_midi_uninit(void)
280 +{
281 +}
282 +
283 +static void *g_recvData;
284 +static pisnd_spi_recv_cb g_recvCallback;
285 +
286 +#define FIFO_SIZE 4096
287 +
288 +static char g_serial_num[11];
289 +static char g_id[25];
290 +static char g_version[5];
291 +
292 +static uint8_t g_ledFlashDuration;
293 +static bool g_ledFlashDurationChanged;
294 +
295 +DEFINE_KFIFO(spi_fifo_in, uint8_t, FIFO_SIZE);
296 +DEFINE_KFIFO(spi_fifo_out, uint8_t, FIFO_SIZE);
297 +
298 +static struct gpio_desc *data_available;
299 +static struct gpio_desc *spi_reset;
300 +
301 +static struct spi_device *pisnd_spi_device;
302 +
303 +static struct workqueue_struct *pisnd_workqueue;
304 +static struct work_struct pisnd_work_process;
305 +
306 +static void pisnd_work_handler(struct work_struct *work);
307 +
308 +static void spi_transfer(const uint8_t *txbuf, uint8_t *rxbuf, int len);
309 +static uint16_t spi_transfer16(uint16_t val);
310 +
311 +static int pisnd_init_workqueues(void)
312 +{
313 + pisnd_workqueue = create_singlethread_workqueue("pisnd_workqueue");
314 + INIT_WORK(&pisnd_work_process, pisnd_work_handler);
315 +
316 + return 0;
317 +}
318 +
319 +static void pisnd_uninit_workqueues(void)
320 +{
321 + flush_workqueue(pisnd_workqueue);
322 + destroy_workqueue(pisnd_workqueue);
323 +
324 + pisnd_workqueue = NULL;
325 +}
326 +
327 +static bool pisnd_spi_has_more(void)
328 +{
329 + return gpiod_get_value(data_available);
330 +}
331 +
332 +static void pisnd_schedule_process(enum task_e task)
333 +{
334 + if (pisnd_spi_device != NULL &&
335 + pisnd_workqueue != NULL &&
336 + !work_pending(&pisnd_work_process)
337 + ) {
338 + printd("schedule: has more = %d\n", pisnd_spi_has_more());
339 + if (task == TASK_PROCESS)
340 + queue_work(pisnd_workqueue, &pisnd_work_process);
341 + }
342 +}
343 +
344 +static irqreturn_t data_available_interrupt_handler(int irq, void *dev_id)
345 +{
346 + if (irq == gpiod_to_irq(data_available) && pisnd_spi_has_more()) {
347 + printd("schedule from irq\n");
348 + pisnd_schedule_process(TASK_PROCESS);
349 + }
350 +
351 + return IRQ_HANDLED;
352 +}
353 +
354 +static DEFINE_SPINLOCK(spilock);
355 +static unsigned long spilockflags;
356 +
357 +static uint16_t spi_transfer16(uint16_t val)
358 +{
359 + uint8_t txbuf[2];
360 + uint8_t rxbuf[2];
361 +
362 + if (!pisnd_spi_device) {
363 + printe("pisnd_spi_device null, returning\n");
364 + return 0;
365 + }
366 +
367 + txbuf[0] = val >> 8;
368 + txbuf[1] = val & 0xff;
369 +
370 + spi_transfer(txbuf, rxbuf, sizeof(txbuf));
371 +
372 + printd("received: %02x%02x\n", rxbuf[0], rxbuf[1]);
373 +
374 + return (rxbuf[0] << 8) | rxbuf[1];
375 +}
376 +
377 +static void spi_transfer(const uint8_t *txbuf, uint8_t *rxbuf, int len)
378 +{
379 + int err;
380 + struct spi_transfer transfer;
381 + struct spi_message msg;
382 +
383 + memset(rxbuf, 0, len);
384 +
385 + if (!pisnd_spi_device) {
386 + printe("pisnd_spi_device null, returning\n");
387 + return;
388 + }
389 +
390 + spi_message_init(&msg);
391 +
392 + memset(&transfer, 0, sizeof(transfer));
393 +
394 + transfer.tx_buf = txbuf;
395 + transfer.rx_buf = rxbuf;
396 + transfer.len = len;
397 + transfer.speed_hz = 100000;
398 + transfer.delay_usecs = 10;
399 + spi_message_add_tail(&transfer, &msg);
400 +
401 + spin_lock_irqsave(&spilock, spilockflags);
402 + err = spi_sync(pisnd_spi_device, &msg);
403 + spin_unlock_irqrestore(&spilock, spilockflags);
404 +
405 + if (err < 0) {
406 + printe("spi_sync error %d\n", err);
407 + return;
408 + }
409 +
410 + printd("hasMore %d\n", pisnd_spi_has_more());
411 +}
412 +
413 +static int spi_read_bytes(char *dst, size_t length, uint8_t *bytesRead)
414 +{
415 + uint16_t rx;
416 + uint8_t size;
417 + uint8_t i;
418 +
419 + memset(dst, 0, length);
420 + *bytesRead = 0;
421 +
422 + rx = spi_transfer16(0);
423 + if (!(rx >> 8))
424 + return -EINVAL;
425 +
426 + size = rx & 0xff;
427 +
428 + if (size > length)
429 + return -EINVAL;
430 +
431 + for (i = 0; i < size; ++i) {
432 + rx = spi_transfer16(0);
433 + if (!(rx >> 8))
434 + return -EINVAL;
435 +
436 + dst[i] = rx & 0xff;
437 + }
438 +
439 + *bytesRead = i;
440 +
441 + return 0;
442 +}
443 +
444 +static int spi_device_match(struct device *dev, void *data)
445 +{
446 + struct spi_device *spi = container_of(dev, struct spi_device, dev);
447 +
448 + printd(" %s %s %dkHz %d bits mode=0x%02X\n",
449 + spi->modalias, dev_name(dev), spi->max_speed_hz/1000,
450 + spi->bits_per_word, spi->mode);
451 +
452 + if (strcmp("pisound-spi", spi->modalias) == 0) {
453 + printi("\tFound!\n");
454 + return 1;
455 + }
456 +
457 + printe("\tNot found!\n");
458 + return 0;
459 +}
460 +
461 +static struct spi_device *pisnd_spi_find_device(void)
462 +{
463 + struct device *dev;
464 +
465 + printi("Searching for spi device...\n");
466 + dev = bus_find_device(&spi_bus_type, NULL, NULL, spi_device_match);
467 + if (dev != NULL)
468 + return container_of(dev, struct spi_device, dev);
469 + else
470 + return NULL;
471 +}
472 +
473 +static void pisnd_work_handler(struct work_struct *work)
474 +{
475 + enum { TRANSFER_SIZE = 4 };
476 + enum { PISOUND_OUTPUT_BUFFER_SIZE = 128 };
477 + enum { MIDI_BYTES_PER_SECOND = 3125 };
478 + int out_buffer_used = 0;
479 + unsigned long now;
480 + uint8_t val;
481 + uint8_t txbuf[TRANSFER_SIZE];
482 + uint8_t rxbuf[TRANSFER_SIZE];
483 + uint8_t midibuf[TRANSFER_SIZE];
484 + int i, n;
485 + bool had_data;
486 +
487 + unsigned long last_transfer_at = jiffies;
488 +
489 + if (work == &pisnd_work_process) {
490 + if (pisnd_spi_device == NULL)
491 + return;
492 +
493 + do {
494 + if (g_midi_output_substream &&
495 + kfifo_avail(&spi_fifo_out) >= sizeof(midibuf)) {
496 +
497 + n = snd_rawmidi_transmit_peek(
498 + g_midi_output_substream,
499 + midibuf, sizeof(midibuf)
500 + );
501 +
502 + if (n > 0) {
503 + for (i = 0; i < n; ++i)
504 + kfifo_put(
505 + &spi_fifo_out,
506 + midibuf[i]
507 + );
508 + snd_rawmidi_transmit_ack(
509 + g_midi_output_substream,
510 + i
511 + );
512 + }
513 + }
514 +
515 + had_data = false;
516 + memset(txbuf, 0, sizeof(txbuf));
517 + for (i = 0; i < sizeof(txbuf) &&
518 + out_buffer_used < PISOUND_OUTPUT_BUFFER_SIZE;
519 + i += 2) {
520 +
521 + val = 0;
522 +
523 + if (g_ledFlashDurationChanged) {
524 + txbuf[i+0] = 0xf0;
525 + txbuf[i+1] = g_ledFlashDuration;
526 + g_ledFlashDuration = 0;
527 + g_ledFlashDurationChanged = false;
528 + } else if (kfifo_get(&spi_fifo_out, &val)) {
529 + txbuf[i+0] = 0x0f;
530 + txbuf[i+1] = val;
531 + ++out_buffer_used;
532 + }
533 + }
534 +
535 + spi_transfer(txbuf, rxbuf, sizeof(txbuf));
536 + /* Estimate the Pisound's MIDI output buffer usage, so
537 + * that we don't overflow it. Space in the buffer should
538 + * be becoming available at the UART MIDI byte transfer
539 + * rate.
540 + */
541 + now = jiffies;
542 + out_buffer_used -=
543 + (MIDI_BYTES_PER_SECOND / HZ) /
544 + (now - last_transfer_at);
545 + if (out_buffer_used < 0)
546 + out_buffer_used = 0;
547 + last_transfer_at = now;
548 +
549 + for (i = 0; i < sizeof(rxbuf); i += 2) {
550 + if (rxbuf[i]) {
551 + kfifo_put(&spi_fifo_in, rxbuf[i+1]);
552 + if (kfifo_len(&spi_fifo_in) > 16 &&
553 + g_recvCallback)
554 + g_recvCallback(g_recvData);
555 + had_data = true;
556 + }
557 + }
558 + } while (had_data
559 + || !kfifo_is_empty(&spi_fifo_out)
560 + || pisnd_spi_has_more()
561 + || g_ledFlashDurationChanged
562 + );
563 +
564 + if (!kfifo_is_empty(&spi_fifo_in) && g_recvCallback)
565 + g_recvCallback(g_recvData);
566 + }
567 +}
568 +
569 +static int pisnd_spi_gpio_init(struct device *dev)
570 +{
571 + spi_reset = gpiod_get_index(dev, "reset", 1, GPIOD_ASIS);
572 + data_available = gpiod_get_index(dev, "data_available", 0, GPIOD_ASIS);
573 +
574 + gpiod_direction_output(spi_reset, 1);
575 + gpiod_direction_input(data_available);
576 +
577 + /* Reset the slave. */
578 + gpiod_set_value(spi_reset, false);
579 + mdelay(1);
580 + gpiod_set_value(spi_reset, true);
581 +
582 + /* Give time for spi slave to start. */
583 + mdelay(64);
584 +
585 + return 0;
586 +}
587 +
588 +static void pisnd_spi_gpio_uninit(void)
589 +{
590 + gpiod_set_value(spi_reset, false);
591 + gpiod_put(spi_reset);
592 + spi_reset = NULL;
593 +
594 + gpiod_put(data_available);
595 + data_available = NULL;
596 +}
597 +
598 +static int pisnd_spi_gpio_irq_init(struct device *dev)
599 +{
600 + return request_irq(
601 + gpiod_to_irq(data_available),
602 + data_available_interrupt_handler,
603 + IRQF_TIMER | IRQF_TRIGGER_RISING,
604 + "data_available_int",
605 + NULL
606 + );
607 +}
608 +
609 +static void pisnd_spi_gpio_irq_uninit(void)
610 +{
611 + free_irq(gpiod_to_irq(data_available), NULL);
612 +}
613 +
614 +static int spi_read_info(void)
615 +{
616 + uint16_t tmp;
617 + uint8_t count;
618 + uint8_t n;
619 + uint8_t i;
620 + uint8_t j;
621 + char buffer[257];
622 + int ret;
623 + char *p;
624 +
625 + memset(g_serial_num, 0, sizeof(g_serial_num));
626 + memset(g_version, 0, sizeof(g_version));
627 + memset(g_id, 0, sizeof(g_id));
628 +
629 + tmp = spi_transfer16(0);
630 +
631 + if (!(tmp >> 8))
632 + return -EINVAL;
633 +
634 + count = tmp & 0xff;
635 +
636 + for (i = 0; i < count; ++i) {
637 + memset(buffer, 0, sizeof(buffer));
638 + ret = spi_read_bytes(buffer, sizeof(buffer)-1, &n);
639 +
640 + if (ret < 0)
641 + return ret;
642 +
643 + switch (i) {
644 + case 0:
645 + if (n != 2)
646 + return -EINVAL;
647 +
648 + snprintf(
649 + g_version,
650 + sizeof(g_version),
651 + "%x.%02x",
652 + buffer[0],
653 + buffer[1]
654 + );
655 + break;
656 + case 1:
657 + if (n >= sizeof(g_serial_num))
658 + return -EINVAL;
659 +
660 + memcpy(g_serial_num, buffer, sizeof(g_serial_num));
661 + break;
662 + case 2:
663 + {
664 + if (n >= sizeof(g_id))
665 + return -EINVAL;
666 +
667 + p = g_id;
668 + for (j = 0; j < n; ++j)
669 + p += sprintf(p, "%02x", buffer[j]);
670 + }
671 + break;
672 + default:
673 + break;
674 + }
675 + }
676 +
677 + return 0;
678 +}
679 +
680 +static int pisnd_spi_init(struct device *dev)
681 +{
682 + int ret;
683 + struct spi_device *spi;
684 +
685 + memset(g_serial_num, 0, sizeof(g_serial_num));
686 + memset(g_id, 0, sizeof(g_id));
687 + memset(g_version, 0, sizeof(g_version));
688 +
689 + spi = pisnd_spi_find_device();
690 +
691 + if (spi != NULL) {
692 + printd("initializing spi!\n");
693 + pisnd_spi_device = spi;
694 + ret = spi_setup(pisnd_spi_device);
695 + } else {
696 + printe("SPI device not found, deferring!\n");
697 + return -EPROBE_DEFER;
698 + }
699 +
700 + ret = pisnd_spi_gpio_init(dev);
701 +
702 + if (ret < 0) {
703 + printe("SPI GPIO init failed: %d\n", ret);
704 + spi_dev_put(pisnd_spi_device);
705 + pisnd_spi_device = NULL;
706 + pisnd_spi_gpio_uninit();
707 + return ret;
708 + }
709 +
710 + ret = spi_read_info();
711 +
712 + if (ret < 0) {
713 + printe("Reading card info failed: %d\n", ret);
714 + spi_dev_put(pisnd_spi_device);
715 + pisnd_spi_device = NULL;
716 + pisnd_spi_gpio_uninit();
717 + return ret;
718 + }
719 +
720 + /* Flash the LEDs. */
721 + spi_transfer16(0xf008);
722 +
723 + ret = pisnd_spi_gpio_irq_init(dev);
724 + if (ret < 0) {
725 + printe("SPI irq request failed: %d\n", ret);
726 + spi_dev_put(pisnd_spi_device);
727 + pisnd_spi_device = NULL;
728 + pisnd_spi_gpio_irq_uninit();
729 + pisnd_spi_gpio_uninit();
730 + }
731 +
732 + ret = pisnd_init_workqueues();
733 + if (ret != 0) {
734 + printe("Workqueue initialization failed: %d\n", ret);
735 + spi_dev_put(pisnd_spi_device);
736 + pisnd_spi_device = NULL;
737 + pisnd_spi_gpio_irq_uninit();
738 + pisnd_spi_gpio_uninit();
739 + pisnd_uninit_workqueues();
740 + return ret;
741 + }
742 +
743 + if (pisnd_spi_has_more()) {
744 + printd("data is available, scheduling from init\n");
745 + pisnd_schedule_process(TASK_PROCESS);
746 + }
747 +
748 + return 0;
749 +}
750 +
751 +static void pisnd_spi_uninit(void)
752 +{
753 + pisnd_uninit_workqueues();
754 +
755 + spi_dev_put(pisnd_spi_device);
756 + pisnd_spi_device = NULL;
757 +
758 + pisnd_spi_gpio_irq_uninit();
759 + pisnd_spi_gpio_uninit();
760 +}
761 +
762 +static void pisnd_spi_flash_leds(uint8_t duration)
763 +{
764 + g_ledFlashDuration = duration;
765 + g_ledFlashDurationChanged = true;
766 + printd("schedule from spi_flash_leds\n");
767 + pisnd_schedule_process(TASK_PROCESS);
768 +}
769 +
770 +static void pisnd_spi_flush(void)
771 +{
772 + while (!kfifo_is_empty(&spi_fifo_out)) {
773 + pisnd_spi_start();
774 + flush_workqueue(pisnd_workqueue);
775 + }
776 +}
777 +
778 +static void pisnd_spi_start(void)
779 +{
780 + printd("schedule from spi_start\n");
781 + pisnd_schedule_process(TASK_PROCESS);
782 +}
783 +
784 +static uint8_t pisnd_spi_recv(uint8_t *buffer, uint8_t length)
785 +{
786 + return kfifo_out(&spi_fifo_in, buffer, length);
787 +}
788 +
789 +static void pisnd_spi_set_callback(pisnd_spi_recv_cb cb, void *data)
790 +{
791 + g_recvData = data;
792 + g_recvCallback = cb;
793 +}
794 +
795 +static const char *pisnd_spi_get_serial(void)
796 +{
797 + if (strlen(g_serial_num))
798 + return g_serial_num;
799 +
800 + return "";
801 +}
802 +
803 +static const char *pisnd_spi_get_id(void)
804 +{
805 + if (strlen(g_id))
806 + return g_id;
807 +
808 + return "";
809 +}
810 +
811 +static const char *pisnd_spi_get_version(void)
812 +{
813 + if (strlen(g_version))
814 + return g_version;
815 +
816 + return "";
817 +}
818 +
819 +static const struct of_device_id pisound_of_match[] = {
820 + { .compatible = "blokaslabs,pisound", },
821 + { .compatible = "blokaslabs,pisound-spi", },
822 + {},
823 +};
824 +
825 +enum {
826 + SWITCH = 0,
827 + VOLUME = 1,
828 +};
829 +
830 +static int pisnd_ctl_info(struct snd_kcontrol *kcontrol,
831 + struct snd_ctl_elem_info *uinfo)
832 +{
833 + if (kcontrol->private_value == SWITCH) {
834 + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
835 + uinfo->count = 1;
836 + uinfo->value.integer.min = 0;
837 + uinfo->value.integer.max = 1;
838 + return 0;
839 + } else if (kcontrol->private_value == VOLUME) {
840 + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
841 + uinfo->count = 1;
842 + uinfo->value.integer.min = 0;
843 + uinfo->value.integer.max = 100;
844 + return 0;
845 + }
846 + return -EINVAL;
847 +}
848 +
849 +static int pisnd_ctl_get(struct snd_kcontrol *kcontrol,
850 + struct snd_ctl_elem_value *ucontrol)
851 +{
852 + if (kcontrol->private_value == SWITCH) {
853 + ucontrol->value.integer.value[0] = 1;
854 + return 0;
855 + } else if (kcontrol->private_value == VOLUME) {
856 + ucontrol->value.integer.value[0] = 100;
857 + return 0;
858 + }
859 +
860 + return -EINVAL;
861 +}
862 +
863 +static struct snd_kcontrol_new pisnd_ctl[] = {
864 + {
865 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
866 + .name = "PCM Playback Switch",
867 + .index = 0,
868 + .private_value = SWITCH,
869 + .access = SNDRV_CTL_ELEM_ACCESS_READ,
870 + .info = pisnd_ctl_info,
871 + .get = pisnd_ctl_get,
872 + },
873 + {
874 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
875 + .name = "PCM Playback Volume",
876 + .index = 0,
877 + .private_value = VOLUME,
878 + .access = SNDRV_CTL_ELEM_ACCESS_READ,
879 + .info = pisnd_ctl_info,
880 + .get = pisnd_ctl_get,
881 + },
882 +};
883 +
884 +static int pisnd_ctl_init(struct snd_card *card)
885 +{
886 + int err, i;
887 +
888 + for (i = 0; i < ARRAY_SIZE(pisnd_ctl); ++i) {
889 + err = snd_ctl_add(card, snd_ctl_new1(&pisnd_ctl[i], NULL));
890 + if (err < 0)
891 + return err;
892 + }
893 +
894 + return 0;
895 +}
896 +
897 +static int pisnd_ctl_uninit(void)
898 +{
899 + return 0;
900 +}
901 +
902 +static struct gpio_desc *osr0, *osr1, *osr2;
903 +static struct gpio_desc *reset;
904 +static struct gpio_desc *button;
905 +
906 +static int pisnd_hw_params(
907 + struct snd_pcm_substream *substream,
908 + struct snd_pcm_hw_params *params
909 + )
910 +{
911 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
912 + struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
913 +
914 + /* Pisound runs on fixed 32 clock counts per channel,
915 + * as generated by the master ADC.
916 + */
917 + snd_soc_dai_set_bclk_ratio(cpu_dai, 32*2);
918 +
919 + printd("rate = %d\n", params_rate(params));
920 + printd("ch = %d\n", params_channels(params));
921 + printd("bits = %u\n",
922 + snd_pcm_format_physical_width(params_format(params)));
923 + printd("format = %d\n", params_format(params));
924 +
925 + gpiod_set_value(reset, false);
926 +
927 + switch (params_rate(params)) {
928 + case 48000:
929 + gpiod_set_value(osr0, true);
930 + gpiod_set_value(osr1, false);
931 + gpiod_set_value(osr2, false);
932 + break;
933 + case 96000:
934 + gpiod_set_value(osr0, true);
935 + gpiod_set_value(osr1, false);
936 + gpiod_set_value(osr2, true);
937 + break;
938 + case 192000:
939 + gpiod_set_value(osr0, true);
940 + gpiod_set_value(osr1, true);
941 + gpiod_set_value(osr2, true);
942 + break;
943 + default:
944 + printe("Unsupported rate %u!\n", params_rate(params));
945 + return -EINVAL;
946 + }
947 +
948 + gpiod_set_value(reset, true);
949 +
950 + return 0;
951 +}
952 +
953 +static unsigned int rates[3] = {
954 + 48000, 96000, 192000
955 +};
956 +
957 +static struct snd_pcm_hw_constraint_list constraints_rates = {
958 + .count = ARRAY_SIZE(rates),
959 + .list = rates,
960 + .mask = 0,
961 +};
962 +
963 +static int pisnd_startup(struct snd_pcm_substream *substream)
964 +{
965 + int err = snd_pcm_hw_constraint_list(
966 + substream->runtime,
967 + 0,
968 + SNDRV_PCM_HW_PARAM_RATE,
969 + &constraints_rates
970 + );
971 +
972 + if (err < 0)
973 + return err;
974 +
975 + err = snd_pcm_hw_constraint_single(
976 + substream->runtime,
977 + SNDRV_PCM_HW_PARAM_CHANNELS,
978 + 2
979 + );
980 +
981 + if (err < 0)
982 + return err;
983 +
984 + err = snd_pcm_hw_constraint_mask64(
985 + substream->runtime,
986 + SNDRV_PCM_HW_PARAM_FORMAT,
987 + SNDRV_PCM_FMTBIT_S16_LE |
988 + SNDRV_PCM_FMTBIT_S24_LE |
989 + SNDRV_PCM_FMTBIT_S32_LE
990 + );
991 +
992 + if (err < 0)
993 + return err;
994 +
995 + return 0;
996 +}
997 +
998 +static struct snd_soc_ops pisnd_ops = {
999 + .startup = pisnd_startup,
1000 + .hw_params = pisnd_hw_params,
1001 +};
1002 +
1003 +static struct snd_soc_dai_link pisnd_dai[] = {
1004 + {
1005 + .name = "pisound",
1006 + .stream_name = "pisound",
1007 + .cpu_dai_name = "bcm2708-i2s.0",
1008 + .codec_dai_name = "snd-soc-dummy-dai",
1009 + .platform_name = "bcm2708-i2s.0",
1010 + .codec_name = "snd-soc-dummy",
1011 + .dai_fmt =
1012 + SND_SOC_DAIFMT_I2S |
1013 + SND_SOC_DAIFMT_NB_NF |
1014 + SND_SOC_DAIFMT_CBM_CFM,
1015 + .ops = &pisnd_ops,
1016 + },
1017 +};
1018 +
1019 +static int pisnd_card_probe(struct snd_soc_card *card)
1020 +{
1021 + int err = pisnd_midi_init(card->snd_card);
1022 +
1023 + if (err < 0) {
1024 + printe("pisnd_midi_init failed: %d\n", err);
1025 + return err;
1026 + }
1027 +
1028 + err = pisnd_ctl_init(card->snd_card);
1029 + if (err < 0) {
1030 + printe("pisnd_ctl_init failed: %d\n", err);
1031 + return err;
1032 + }
1033 +
1034 + return 0;
1035 +}
1036 +
1037 +static int pisnd_card_remove(struct snd_soc_card *card)
1038 +{
1039 + pisnd_ctl_uninit();
1040 + pisnd_midi_uninit();
1041 + return 0;
1042 +}
1043 +
1044 +static struct snd_soc_card pisnd_card = {
1045 + .name = "pisound",
1046 + .owner = THIS_MODULE,
1047 + .dai_link = pisnd_dai,
1048 + .num_links = ARRAY_SIZE(pisnd_dai),
1049 + .probe = pisnd_card_probe,
1050 + .remove = pisnd_card_remove,
1051 +};
1052 +
1053 +static int pisnd_init_gpio(struct device *dev)
1054 +{
1055 + osr0 = gpiod_get_index(dev, "osr", 0, GPIOD_ASIS);
1056 + osr1 = gpiod_get_index(dev, "osr", 1, GPIOD_ASIS);
1057 + osr2 = gpiod_get_index(dev, "osr", 2, GPIOD_ASIS);
1058 +
1059 + reset = gpiod_get_index(dev, "reset", 0, GPIOD_ASIS);
1060 +
1061 + button = gpiod_get_index(dev, "button", 0, GPIOD_ASIS);
1062 +
1063 + gpiod_direction_output(osr0, 1);
1064 + gpiod_direction_output(osr1, 1);
1065 + gpiod_direction_output(osr2, 1);
1066 + gpiod_direction_output(reset, 1);
1067 +
1068 + gpiod_set_value(reset, false);
1069 + gpiod_set_value(osr0, true);
1070 + gpiod_set_value(osr1, false);
1071 + gpiod_set_value(osr2, false);
1072 + gpiod_set_value(reset, true);
1073 +
1074 + gpiod_export(button, false);
1075 +
1076 + return 0;
1077 +}
1078 +
1079 +static int pisnd_uninit_gpio(void)
1080 +{
1081 + int i;
1082 +
1083 + struct gpio_desc **gpios[] = {
1084 + &osr0, &osr1, &osr2, &reset, &button,
1085 + };
1086 +
1087 + gpiod_unexport(button);
1088 +
1089 + for (i = 0; i < ARRAY_SIZE(gpios); ++i) {
1090 + if (*gpios[i] == NULL) {
1091 + printd("weird, GPIO[%d] is NULL already\n", i);
1092 + continue;
1093 + }
1094 +
1095 + gpiod_put(*gpios[i]);
1096 + *gpios[i] = NULL;
1097 + }
1098 +
1099 + return 0;
1100 +}
1101 +
1102 +static struct kobject *pisnd_kobj;
1103 +
1104 +static ssize_t pisnd_serial_show(
1105 + struct kobject *kobj,
1106 + struct kobj_attribute *attr,
1107 + char *buf
1108 + )
1109 +{
1110 + return sprintf(buf, "%s\n", pisnd_spi_get_serial());
1111 +}
1112 +
1113 +static ssize_t pisnd_id_show(
1114 + struct kobject *kobj,
1115 + struct kobj_attribute *attr,
1116 + char *buf
1117 + )
1118 +{
1119 + return sprintf(buf, "%s\n", pisnd_spi_get_id());
1120 +}
1121 +
1122 +static ssize_t pisnd_version_show(
1123 + struct kobject *kobj,
1124 + struct kobj_attribute *attr,
1125 + char *buf
1126 + )
1127 +{
1128 + return sprintf(buf, "%s\n", pisnd_spi_get_version());
1129 +}
1130 +
1131 +static ssize_t pisnd_led_store(
1132 + struct kobject *kobj,
1133 + struct kobj_attribute *attr,
1134 + const char *buf,
1135 + size_t length
1136 + )
1137 +{
1138 + uint32_t timeout;
1139 + int err;
1140 +
1141 + err = kstrtou32(buf, 10, &timeout);
1142 +
1143 + if (err == 0 && timeout <= 255)
1144 + pisnd_spi_flash_leds(timeout);
1145 +
1146 + return length;
1147 +}
1148 +
1149 +static struct kobj_attribute pisnd_serial_attribute =
1150 + __ATTR(serial, 0444, pisnd_serial_show, NULL);
1151 +static struct kobj_attribute pisnd_id_attribute =
1152 + __ATTR(id, 0444, pisnd_id_show, NULL);
1153 +static struct kobj_attribute pisnd_version_attribute =
1154 + __ATTR(version, 0444, pisnd_version_show, NULL);
1155 +static struct kobj_attribute pisnd_led_attribute =
1156 + __ATTR(led, 0644, NULL, pisnd_led_store);
1157 +
1158 +static struct attribute *attrs[] = {
1159 + &pisnd_serial_attribute.attr,
1160 + &pisnd_id_attribute.attr,
1161 + &pisnd_version_attribute.attr,
1162 + &pisnd_led_attribute.attr,
1163 + NULL
1164 +};
1165 +
1166 +static struct attribute_group attr_group = { .attrs = attrs };
1167 +
1168 +static int pisnd_probe(struct platform_device *pdev)
1169 +{
1170 + int ret = 0;
1171 + int i;
1172 +
1173 + ret = pisnd_spi_init(&pdev->dev);
1174 + if (ret < 0) {
1175 + printe("pisnd_spi_init failed: %d\n", ret);
1176 + return ret;
1177 + }
1178 +
1179 + printi("Detected Pisound card:\n");
1180 + printi("\tSerial: %s\n", pisnd_spi_get_serial());
1181 + printi("\tVersion: %s\n", pisnd_spi_get_version());
1182 + printi("\tId: %s\n", pisnd_spi_get_id());
1183 +
1184 + pisnd_kobj = kobject_create_and_add("pisound", kernel_kobj);
1185 + if (!pisnd_kobj) {
1186 + pisnd_spi_uninit();
1187 + return -ENOMEM;
1188 + }
1189 +
1190 + ret = sysfs_create_group(pisnd_kobj, &attr_group);
1191 + if (ret < 0) {
1192 + pisnd_spi_uninit();
1193 + kobject_put(pisnd_kobj);
1194 + return -ENOMEM;
1195 + }
1196 +
1197 + pisnd_init_gpio(&pdev->dev);
1198 + pisnd_card.dev = &pdev->dev;
1199 +
1200 + if (pdev->dev.of_node) {
1201 + struct device_node *i2s_node;
1202 +
1203 + i2s_node = of_parse_phandle(
1204 + pdev->dev.of_node,
1205 + "i2s-controller",
1206 + 0
1207 + );
1208 +
1209 + for (i = 0; i < pisnd_card.num_links; ++i) {
1210 + struct snd_soc_dai_link *dai = &pisnd_dai[i];
1211 +
1212 + if (i2s_node) {
1213 + dai->cpu_dai_name = NULL;
1214 + dai->cpu_of_node = i2s_node;
1215 + dai->platform_name = NULL;
1216 + dai->platform_of_node = i2s_node;
1217 + dai->stream_name = pisnd_spi_get_serial();
1218 + }
1219 + }
1220 + }
1221 +
1222 + ret = snd_soc_register_card(&pisnd_card);
1223 +
1224 + if (ret < 0) {
1225 + if (ret != -EPROBE_DEFER)
1226 + printe("snd_soc_register_card() failed: %d\n", ret);
1227 + pisnd_uninit_gpio();
1228 + kobject_put(pisnd_kobj);
1229 + pisnd_spi_uninit();
1230 + }
1231 +
1232 + return ret;
1233 +}
1234 +
1235 +static int pisnd_remove(struct platform_device *pdev)
1236 +{
1237 + printi("Unloading.\n");
1238 +
1239 + if (pisnd_kobj) {
1240 + kobject_put(pisnd_kobj);
1241 + pisnd_kobj = NULL;
1242 + }
1243 +
1244 + pisnd_spi_uninit();
1245 +
1246 + /* Turn off */
1247 + gpiod_set_value(reset, false);
1248 + pisnd_uninit_gpio();
1249 +
1250 + return snd_soc_unregister_card(&pisnd_card);
1251 +}
1252 +
1253 +MODULE_DEVICE_TABLE(of, pisound_of_match);
1254 +
1255 +static struct platform_driver pisnd_driver = {
1256 + .driver = {
1257 + .name = "snd-rpi-pisound",
1258 + .owner = THIS_MODULE,
1259 + .of_match_table = pisound_of_match,
1260 + },
1261 + .probe = pisnd_probe,
1262 + .remove = pisnd_remove,
1263 +};
1264 +
1265 +module_platform_driver(pisnd_driver);
1266 +
1267 +MODULE_AUTHOR("Giedrius Trainavicius <giedrius@blokas.io>");
1268 +MODULE_DESCRIPTION("ASoC Driver for Pisound, https://blokas.io/pisound");
1269 +MODULE_LICENSE("GPL v2");