lantiq: fix broadcasts and vlans in two iface mode
[oweals/openwrt.git] / target / linux / brcm2708 / patches-4.9 / 0084-Support-for-Blokas-Labs-pisound-board.patch
1 From 7d8efd6f3198fd3dafe5a74003616a2aea5dc6c5 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] 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  .../devicetree/bindings/vendor-prefixes.txt        |   1 +
13  arch/arm/boot/dts/overlays/pisound-overlay.dts     |  94 +-
14  sound/soc/bcm/Kconfig                              |   6 +
15  sound/soc/bcm/Makefile                             |   2 +
16  sound/soc/bcm/pisound.c                            | 989 +++++++++++++++++++++
17  5 files changed, 1048 insertions(+), 44 deletions(-)
18  create mode 100644 sound/soc/bcm/pisound.c
19
20 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt
21 +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
22 @@ -40,6 +40,7 @@ auvidea Auvidea GmbH
23  avago  Avago Technologies
24  avic   Shanghai AVIC Optoelectronics Co., Ltd.
25  axis   Axis Communications AB
26 +blokaslabs     Vilniaus Blokas UAB
27  boe    BOE Technology Group Co., Ltd.
28  bosch  Bosch Sensortec GmbH
29  boundary       Boundary Devices Inc.
30 --- a/arch/arm/boot/dts/overlays/pisound-overlay.dts
31 +++ b/arch/arm/boot/dts/overlays/pisound-overlay.dts
32 @@ -26,6 +26,54 @@
33         compatible = "brcm,bcm2708";
34  
35         fragment@0 {
36 +               target = <&spi0>;
37 +               __overlay__ {
38 +                       status = "okay";
39 +               };
40 +       };
41 +
42 +       fragment@1 {
43 +               target = <&spidev0>;
44 +               __overlay__ {
45 +                       status = "disabled";
46 +               };
47 +       };
48 +
49 +       fragment@2 {
50 +               target = <&spidev1>;
51 +               __overlay__ {
52 +                       status = "okay";
53 +               };
54 +       };
55 +
56 +       fragment@3 {
57 +               target = <&spi0>;
58 +               __overlay__ {
59 +                       #address-cells = <1>;
60 +                       #size-cells = <0>;
61 +
62 +                       pisound_spi: pisound_spi@0{
63 +                               compatible = "blokaslabs,pisound-spi";
64 +                               reg = <0>;
65 +                               pinctrl-names = "default";
66 +                               pinctrl-0 = <&spi0_pins>;
67 +                               spi-max-frequency = <1000000>;
68 +                       };
69 +               };
70 +       };
71 +
72 +       fragment@4 {
73 +               target-path = "/";
74 +               __overlay__ {
75 +                       pcm5102a-codec {
76 +                               #sound-dai-cells = <0>;
77 +                               compatible = "ti,pcm5102a";
78 +                               status = "okay";
79 +                       };
80 +               };
81 +       };
82 +
83 +       fragment@5 {
84                 target = <&sound>;
85                 __overlay__ {
86                         compatible = "blokaslabs,pisound";
87 @@ -49,7 +97,7 @@
88                 };
89         };
90  
91 -       fragment@1 {
92 +       fragment@6 {
93                 target = <&gpio>;
94                 __overlay__ {
95                         pinctrl-names = "default";
96 @@ -63,52 +111,10 @@
97                 };
98         };
99  
100 -       fragment@2 {
101 +       fragment@7 {
102                 target = <&i2s>;
103                 __overlay__ {
104                         status = "okay";
105                 };
106         };
107 -
108 -       fragment@3 {
109 -               target-path = "/";
110 -               __overlay__ {
111 -                       pcm5102a-codec {
112 -                               #sound-dai-cells = <0>;
113 -                               compatible = "ti,pcm5102a";
114 -                               status = "okay";
115 -                       };
116 -               };
117 -       };
118 -
119 -       fragment@4 {
120 -               target = <&spi0>;
121 -               __overlay__ {
122 -                       status = "okay";
123 -
124 -                       spidev@0{
125 -                               status = "disabled";
126 -                       };
127 -
128 -                       spidev@1{
129 -                               status = "okay";
130 -                       };
131 -               };
132 -       };
133 -
134 -       fragment@5 {
135 -               target = <&spi0>;
136 -               __overlay__ {
137 -                       #address-cells = <1>;
138 -                       #size-cells = <0>;
139 -
140 -                       pisound_spi: pisound_spi@0{
141 -                               compatible = "blokaslabs,pisound-spi";
142 -                               reg = <0>;
143 -                               pinctrl-names = "default";
144 -                               pinctrl-0 = <&spi0_pins>;
145 -                               spi-max-frequency = <1000000>;
146 -                       };
147 -               };
148 -       };
149  };
150 --- a/sound/soc/bcm/Kconfig
151 +++ b/sound/soc/bcm/Kconfig
152 @@ -130,3 +130,9 @@ config SND_BCM2708_SOC_ALLO_PIANO_DAC
153         select SND_SOC_PCM512x_I2C
154         help
155           Say Y or M if you want to add support for Allo Piano DAC.
156 +
157 +config SND_PISOUND
158 +       tristate "Support for Blokas Labs pisound"
159 +       depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
160 +       help
161 +         Say Y or M if you want to add support for Blokas Labs pisound.
162 --- a/sound/soc/bcm/Makefile
163 +++ b/sound/soc/bcm/Makefile
164 @@ -25,6 +25,7 @@ snd-soc-audioinjector-pi-soundcard-objs
165  snd-soc-digidac1-soundcard-objs := digidac1-soundcard.o
166  snd-soc-dionaudio-loco-objs := dionaudio_loco.o
167  snd-soc-allo-piano-dac-objs := allo-piano-dac.o
168 +snd-soc-pisound-objs := pisound.o
169  
170  obj-$(CONFIG_SND_BCM2708_SOC_ADAU1977_ADC) += snd-soc-adau1977-adc.o
171  obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP) += snd-soc-hifiberry-amp.o
172 @@ -42,3 +43,4 @@ obj-$(CONFIG_SND_AUDIOINJECTOR_PI_SOUNDC
173  obj-$(CONFIG_SND_DIGIDAC1_SOUNDCARD) += snd-soc-digidac1-soundcard.o
174  obj-$(CONFIG_SND_BCM2708_SOC_DIONAUDIO_LOCO) += snd-soc-dionaudio-loco.o
175  obj-$(CONFIG_SND_BCM2708_SOC_ALLO_PIANO_DAC) += snd-soc-allo-piano-dac.o
176 +obj-$(CONFIG_SND_PISOUND) += snd-soc-pisound.o
177 --- /dev/null
178 +++ b/sound/soc/bcm/pisound.c
179 @@ -0,0 +1,989 @@
180 +/*
181 + * pisound Linux kernel module.
182 + * Copyright (C) 2016  Vilniaus Blokas UAB, http://blokas.io/pisound
183 + *
184 + * This program is free software; you can redistribute it and/or
185 + * modify it under the terms of the GNU General Public License
186 + * as published by the Free Software Foundation; version 2 of the
187 + * License.
188 + *
189 + * This program is distributed in the hope that it will be useful,
190 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
191 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
192 + * GNU General Public License for more details.
193 + *
194 + * You should have received a copy of the GNU General Public License
195 + * along with this program; if not, write to the Free Software
196 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
197 + * MA  02110-1301, USA.
198 + */
199 +
200 +#include <linux/init.h>
201 +#include <linux/module.h>
202 +#include <linux/platform_device.h>
203 +#include <linux/gpio.h>
204 +#include <linux/kobject.h>
205 +#include <linux/sysfs.h>
206 +#include <linux/delay.h>
207 +#include <linux/spi/spi.h>
208 +#include <linux/interrupt.h>
209 +#include <linux/kfifo.h>
210 +
211 +#include <sound/core.h>
212 +#include <sound/pcm.h>
213 +#include <sound/pcm_params.h>
214 +#include <sound/soc.h>
215 +#include <sound/jack.h>
216 +#include <sound/rawmidi.h>
217 +#include <sound/asequencer.h>
218 +
219 +static int pisnd_spi_init(struct device *dev);
220 +static void pisnd_spi_uninit(void);
221 +
222 +static void pisnd_spi_send(uint8_t val);
223 +static uint8_t pisnd_spi_recv(uint8_t *buffer, uint8_t length);
224 +
225 +typedef void (*pisnd_spi_recv_cb)(void *data);
226 +static void pisnd_spi_set_callback(pisnd_spi_recv_cb cb, void *data);
227 +
228 +static const char *pisnd_spi_get_serial(void);
229 +static const char *pisnd_spi_get_id(void);
230 +static const char *pisnd_spi_get_version(void);
231 +
232 +static int pisnd_midi_init(struct snd_card *card);
233 +static void pisnd_midi_uninit(void);
234 +
235 +#define PISOUND_LOG_PREFIX "pisound: "
236 +
237 +#ifdef DEBUG
238 +#      define printd(...) pr_alert(PISOUND_LOG_PREFIX __VA_ARGS__)
239 +#else
240 +#      define printd(...) do {} while (0)
241 +#endif
242 +
243 +#define printe(...) pr_err(PISOUND_LOG_PREFIX __VA_ARGS__)
244 +#define printi(...) pr_info(PISOUND_LOG_PREFIX __VA_ARGS__)
245 +
246 +static int pisnd_output_open(struct snd_rawmidi_substream *substream)
247 +{
248 +       return 0;
249 +}
250 +
251 +static int pisnd_output_close(struct snd_rawmidi_substream *substream)
252 +{
253 +       return 0;
254 +}
255 +
256 +static void pisnd_output_trigger(
257 +       struct snd_rawmidi_substream *substream,
258 +       int up
259 +       )
260 +{
261 +       uint8_t data;
262 +
263 +       if (!up)
264 +               return;
265 +
266 +       while (snd_rawmidi_transmit_peek(substream, &data, 1)) {
267 +               pisnd_spi_send(data);
268 +               snd_rawmidi_transmit_ack(substream, 1);
269 +       }
270 +}
271 +
272 +static void pisnd_output_drain(struct snd_rawmidi_substream *substream)
273 +{
274 +       uint8_t data;
275 +
276 +       while (snd_rawmidi_transmit_peek(substream, &data, 1)) {
277 +               pisnd_spi_send(data);
278 +
279 +               snd_rawmidi_transmit_ack(substream, 1);
280 +       }
281 +}
282 +
283 +static int pisnd_input_open(struct snd_rawmidi_substream *substream)
284 +{
285 +       return 0;
286 +}
287 +
288 +static int pisnd_input_close(struct snd_rawmidi_substream *substream)
289 +{
290 +       return 0;
291 +}
292 +
293 +static void pisnd_midi_recv_callback(void *substream)
294 +{
295 +       uint8_t data[128];
296 +       uint8_t n = 0;
297 +
298 +       while ((n = pisnd_spi_recv(data, sizeof(data)))) {
299 +               int res = snd_rawmidi_receive(substream, data, n);
300 +               (void)res;
301 +               printd("midi recv 0x%02x, res = %d\n", data, res);
302 +       }
303 +}
304 +
305 +static void pisnd_input_trigger(struct snd_rawmidi_substream *substream, int up)
306 +{
307 +       if (up) {
308 +               pisnd_spi_set_callback(pisnd_midi_recv_callback, substream);
309 +               pisnd_midi_recv_callback(substream);
310 +       } else {
311 +               pisnd_spi_set_callback(NULL, NULL);
312 +       }
313 +}
314 +
315 +static struct snd_rawmidi *g_rmidi;
316 +
317 +static struct snd_rawmidi_ops pisnd_output_ops = {
318 +       .open = pisnd_output_open,
319 +       .close = pisnd_output_close,
320 +       .trigger = pisnd_output_trigger,
321 +       .drain = pisnd_output_drain,
322 +};
323 +
324 +static struct snd_rawmidi_ops pisnd_input_ops = {
325 +       .open = pisnd_input_open,
326 +       .close = pisnd_input_close,
327 +       .trigger = pisnd_input_trigger,
328 +};
329 +
330 +static void pisnd_get_port_info(
331 +       struct snd_rawmidi *rmidi,
332 +       int number,
333 +       struct snd_seq_port_info *seq_port_info
334 +       )
335 +{
336 +       seq_port_info->type =
337 +               SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC |
338 +               SNDRV_SEQ_PORT_TYPE_HARDWARE |
339 +               SNDRV_SEQ_PORT_TYPE_PORT;
340 +       seq_port_info->midi_voices = 0;
341 +}
342 +
343 +static struct snd_rawmidi_global_ops pisnd_global_ops = {
344 +       .get_port_info = pisnd_get_port_info,
345 +};
346 +
347 +static int pisnd_midi_init(struct snd_card *card)
348 +{
349 +       int err = snd_rawmidi_new(card, "pisound MIDI", 0, 1, 1, &g_rmidi);
350 +
351 +       if (err < 0) {
352 +               printe("snd_rawmidi_new failed: %d\n", err);
353 +               return err;
354 +       }
355 +
356 +       strcpy(g_rmidi->name, "pisound MIDI ");
357 +       strcat(g_rmidi->name, pisnd_spi_get_serial());
358 +
359 +       g_rmidi->info_flags =
360 +               SNDRV_RAWMIDI_INFO_OUTPUT |
361 +               SNDRV_RAWMIDI_INFO_INPUT |
362 +               SNDRV_RAWMIDI_INFO_DUPLEX;
363 +
364 +       g_rmidi->ops = &pisnd_global_ops;
365 +
366 +       g_rmidi->private_data = (void *)0;
367 +
368 +       snd_rawmidi_set_ops(
369 +               g_rmidi,
370 +               SNDRV_RAWMIDI_STREAM_OUTPUT,
371 +               &pisnd_output_ops
372 +               );
373 +
374 +       snd_rawmidi_set_ops(
375 +               g_rmidi,
376 +               SNDRV_RAWMIDI_STREAM_INPUT,
377 +               &pisnd_input_ops
378 +               );
379 +
380 +       return 0;
381 +}
382 +
383 +static void pisnd_midi_uninit(void)
384 +{
385 +}
386 +
387 +static void *g_recvData;
388 +static pisnd_spi_recv_cb g_recvCallback;
389 +
390 +#define FIFO_SIZE 512
391 +
392 +static char g_serial_num[11];
393 +static char g_id[25];
394 +static char g_version[5];
395 +
396 +DEFINE_KFIFO(spi_fifo_in,  uint8_t, FIFO_SIZE);
397 +DEFINE_KFIFO(spi_fifo_out, uint8_t, FIFO_SIZE);
398 +
399 +static struct gpio_desc *data_available;
400 +static struct gpio_desc *spi_reset;
401 +
402 +static struct spi_device *pisnd_spi_device;
403 +
404 +static struct workqueue_struct *pisnd_workqueue;
405 +static struct work_struct pisnd_work_process;
406 +
407 +static void pisnd_work_handler(struct work_struct *work);
408 +
409 +static uint16_t spi_transfer16(uint16_t val);
410 +
411 +static int pisnd_init_workqueues(void)
412 +{
413 +       pisnd_workqueue = create_singlethread_workqueue("pisnd_workqueue");
414 +       INIT_WORK(&pisnd_work_process, pisnd_work_handler);
415 +
416 +       return 0;
417 +}
418 +
419 +static void pisnd_uninit_workqueues(void)
420 +{
421 +       flush_workqueue(pisnd_workqueue);
422 +       destroy_workqueue(pisnd_workqueue);
423 +
424 +       pisnd_workqueue = NULL;
425 +}
426 +
427 +static bool pisnd_spi_has_more(void)
428 +{
429 +       return gpiod_get_value(data_available);
430 +}
431 +
432 +enum task_e {
433 +       TASK_PROCESS = 0,
434 +};
435 +
436 +static void pisnd_schedule_process(enum task_e task)
437 +{
438 +       if (pisnd_spi_device != NULL &&
439 +               pisnd_workqueue != NULL &&
440 +               !work_pending(&pisnd_work_process)
441 +               ) {
442 +               printd("schedule: has more = %d\n", pisnd_spi_has_more());
443 +               if (task == TASK_PROCESS)
444 +                       queue_work(pisnd_workqueue, &pisnd_work_process);
445 +       }
446 +}
447 +
448 +static irqreturn_t data_available_interrupt_handler(int irq, void *dev_id)
449 +{
450 +       if (irq == gpiod_to_irq(data_available) && pisnd_spi_has_more()) {
451 +               printd("schedule from irq\n");
452 +               pisnd_schedule_process(TASK_PROCESS);
453 +       }
454 +
455 +       return IRQ_HANDLED;
456 +}
457 +
458 +static DEFINE_SPINLOCK(spilock);
459 +static unsigned long spilockflags;
460 +
461 +static uint16_t spi_transfer16(uint16_t val)
462 +{
463 +       int err;
464 +       struct spi_transfer transfer;
465 +       struct spi_message msg;
466 +       uint8_t txbuf[2];
467 +       uint8_t rxbuf[2];
468 +
469 +       if (!pisnd_spi_device) {
470 +               printe("pisnd_spi_device null, returning\n");
471 +               return 0;
472 +       }
473 +
474 +       spi_message_init(&msg);
475 +
476 +       memset(&transfer, 0, sizeof(transfer));
477 +       memset(&rxbuf, 0, sizeof(rxbuf));
478 +
479 +       txbuf[0] = val >> 8;
480 +       txbuf[1] = val & 0xff;
481 +
482 +       transfer.tx_buf = &txbuf;
483 +       transfer.rx_buf = &rxbuf;
484 +       transfer.len = sizeof(txbuf);
485 +       transfer.speed_hz = 125000;
486 +       transfer.delay_usecs = 100;
487 +       spi_message_add_tail(&transfer, &msg);
488 +
489 +       spin_lock_irqsave(&spilock, spilockflags);
490 +       err = spi_sync(pisnd_spi_device, &msg);
491 +       spin_unlock_irqrestore(&spilock, spilockflags);
492 +
493 +       if (err < 0) {
494 +               printe("spi_sync error %d\n", err);
495 +               return 0;
496 +       }
497 +
498 +       printd("received: %02x%02x\n", rxbuf[0], rxbuf[1]);
499 +       printd("hasMore %d\n", pisnd_spi_has_more());
500 +
501 +       return (rxbuf[0] << 8) | rxbuf[1];
502 +}
503 +
504 +static int spi_read_bytes(char *dst, size_t length, uint8_t *bytesRead)
505 +{
506 +       uint16_t rx;
507 +       uint8_t size;
508 +       uint8_t i;
509 +
510 +       memset(dst, 0, length);
511 +       *bytesRead = 0;
512 +
513 +        rx = spi_transfer16(0);
514 +       if (!(rx >> 8))
515 +               return -EINVAL;
516 +
517 +       size = rx & 0xff;
518 +
519 +       if (size > length)
520 +               return -EINVAL;
521 +
522 +       for (i = 0; i < size; ++i) {
523 +               rx = spi_transfer16(0);
524 +               if (!(rx >> 8))
525 +                       return -EINVAL;
526 +
527 +               dst[i] = rx & 0xff;
528 +       }
529 +
530 +       *bytesRead = i;
531 +
532 +       return 0;
533 +}
534 +
535 +static int spi_device_match(struct device *dev, void *data)
536 +{
537 +       struct spi_device *spi = container_of(dev, struct spi_device, dev);
538 +
539 +       printd("      %s %s %dkHz %d bits mode=0x%02X\n",
540 +               spi->modalias, dev_name(dev), spi->max_speed_hz/1000,
541 +               spi->bits_per_word, spi->mode);
542 +
543 +       if (strcmp("pisound-spi", spi->modalias) == 0) {
544 +               printi("\tFound!\n");
545 +               return 1;
546 +       }
547 +
548 +       printe("\tNot found!\n");
549 +       return 0;
550 +}
551 +
552 +static struct spi_device *pisnd_spi_find_device(void)
553 +{
554 +       struct device *dev;
555 +
556 +       printi("Searching for spi device...\n");
557 +       dev = bus_find_device(&spi_bus_type, NULL, NULL, spi_device_match);
558 +       if (dev != NULL)
559 +               return container_of(dev, struct spi_device, dev);
560 +       else
561 +               return NULL;
562 +}
563 +
564 +static void pisnd_work_handler(struct work_struct *work)
565 +{
566 +       uint16_t rx;
567 +       uint16_t tx;
568 +       uint8_t val;
569 +
570 +       if (work == &pisnd_work_process) {
571 +               if (pisnd_spi_device == NULL)
572 +                       return;
573 +
574 +               do {
575 +                       val = 0;
576 +                       tx = 0;
577 +
578 +                       if (kfifo_get(&spi_fifo_out, &val))
579 +                               tx = 0x0f00 | val;
580 +
581 +                       rx = spi_transfer16(tx);
582 +
583 +                       if (rx & 0xff00) {
584 +                               kfifo_put(&spi_fifo_in, rx & 0xff);
585 +                               if (kfifo_len(&spi_fifo_in) > 16
586 +                                       && g_recvCallback)
587 +                                       g_recvCallback(g_recvData);
588 +                       }
589 +               } while (rx != 0
590 +                       || !kfifo_is_empty(&spi_fifo_out)
591 +                       || pisnd_spi_has_more()
592 +                       );
593 +
594 +               if (!kfifo_is_empty(&spi_fifo_in) && g_recvCallback)
595 +                       g_recvCallback(g_recvData);
596 +       }
597 +}
598 +
599 +static int pisnd_spi_gpio_init(struct device *dev)
600 +{
601 +       spi_reset = gpiod_get_index(dev, "reset", 1, GPIOD_ASIS);
602 +       data_available = gpiod_get_index(dev, "data_available", 0, GPIOD_ASIS);
603 +
604 +       gpiod_direction_output(spi_reset, 1);
605 +       gpiod_direction_input(data_available);
606 +
607 +       /* Reset the slave. */
608 +       gpiod_set_value(spi_reset, false);
609 +       mdelay(1);
610 +       gpiod_set_value(spi_reset, true);
611 +
612 +       /* Give time for spi slave to start. */
613 +       mdelay(64);
614 +
615 +       return 0;
616 +}
617 +
618 +static void pisnd_spi_gpio_uninit(void)
619 +{
620 +       gpiod_set_value(spi_reset, false);
621 +       gpiod_put(spi_reset);
622 +       spi_reset = NULL;
623 +
624 +       gpiod_put(data_available);
625 +       data_available = NULL;
626 +}
627 +
628 +static int pisnd_spi_gpio_irq_init(struct device *dev)
629 +{
630 +       return request_irq(
631 +               gpiod_to_irq(data_available),
632 +               data_available_interrupt_handler,
633 +               IRQF_TIMER | IRQF_TRIGGER_RISING,
634 +               "data_available_int",
635 +               NULL
636 +               );
637 +}
638 +
639 +static void pisnd_spi_gpio_irq_uninit(void)
640 +{
641 +       free_irq(gpiod_to_irq(data_available), NULL);
642 +}
643 +
644 +static int spi_read_info(void)
645 +{
646 +       uint16_t tmp;
647 +       uint8_t count;
648 +       uint8_t n;
649 +       uint8_t i;
650 +       uint8_t j;
651 +       char buffer[257];
652 +       int ret;
653 +       char *p;
654 +
655 +       memset(g_serial_num, 0, sizeof(g_serial_num));
656 +       memset(g_version, 0, sizeof(g_version));
657 +       memset(g_id, 0, sizeof(g_id));
658 +
659 +       tmp = spi_transfer16(0);
660 +
661 +       if (!(tmp >> 8))
662 +               return -EINVAL;
663 +
664 +        count = tmp & 0xff;
665 +
666 +       for (i = 0; i < count; ++i) {
667 +               memset(buffer, 0, sizeof(buffer));
668 +               ret = spi_read_bytes(buffer, sizeof(buffer)-1, &n);
669 +
670 +               if (ret < 0)
671 +                       return ret;
672 +
673 +               switch (i) {
674 +               case 0:
675 +                       if (n != 2)
676 +                               return -EINVAL;
677 +
678 +                       snprintf(
679 +                               g_version,
680 +                               sizeof(g_version),
681 +                               "%x.%02x",
682 +                               buffer[0],
683 +                               buffer[1]
684 +                               );
685 +                       break;
686 +               case 1:
687 +                       if (n >= sizeof(g_serial_num))
688 +                               return -EINVAL;
689 +
690 +                       memcpy(g_serial_num, buffer, sizeof(g_serial_num));
691 +                       break;
692 +               case 2:
693 +                       {
694 +                               if (n >= sizeof(g_id))
695 +                                       return -EINVAL;
696 +
697 +                               p = g_id;
698 +                               for (j = 0; j < n; ++j)
699 +                                       p += sprintf(p, "%02x", buffer[j]);
700 +                       }
701 +                       break;
702 +               default:
703 +                       break;
704 +               }
705 +       }
706 +
707 +       return 0;
708 +}
709 +
710 +static int pisnd_spi_init(struct device *dev)
711 +{
712 +       int ret;
713 +       struct spi_device *spi;
714 +
715 +       memset(g_serial_num, 0, sizeof(g_serial_num));
716 +       memset(g_id, 0, sizeof(g_id));
717 +       memset(g_version, 0, sizeof(g_version));
718 +
719 +       spi = pisnd_spi_find_device();
720 +
721 +       if (spi != NULL) {
722 +               printd("initializing spi!\n");
723 +               pisnd_spi_device = spi;
724 +               ret = spi_setup(pisnd_spi_device);
725 +       } else {
726 +               printe("SPI device not found, deferring!\n");
727 +               return -EPROBE_DEFER;
728 +       }
729 +
730 +       ret = pisnd_spi_gpio_init(dev);
731 +
732 +       if (ret < 0) {
733 +               printe("SPI GPIO init failed: %d\n", ret);
734 +               spi_dev_put(pisnd_spi_device);
735 +               pisnd_spi_device = NULL;
736 +               pisnd_spi_gpio_uninit();
737 +               return ret;
738 +       }
739 +
740 +       ret = spi_read_info();
741 +
742 +       if (ret < 0) {
743 +               printe("Reading card info failed: %d\n", ret);
744 +               spi_dev_put(pisnd_spi_device);
745 +               pisnd_spi_device = NULL;
746 +               pisnd_spi_gpio_uninit();
747 +               return ret;
748 +       }
749 +
750 +       /* Flash the LEDs. */
751 +       spi_transfer16(0xf000);
752 +
753 +       ret = pisnd_spi_gpio_irq_init(dev);
754 +       if (ret < 0) {
755 +               printe("SPI irq request failed: %d\n", ret);
756 +               spi_dev_put(pisnd_spi_device);
757 +               pisnd_spi_device = NULL;
758 +               pisnd_spi_gpio_irq_uninit();
759 +               pisnd_spi_gpio_uninit();
760 +       }
761 +
762 +       ret = pisnd_init_workqueues();
763 +       if (ret != 0) {
764 +               printe("Workqueue initialization failed: %d\n", ret);
765 +               spi_dev_put(pisnd_spi_device);
766 +               pisnd_spi_device = NULL;
767 +               pisnd_spi_gpio_irq_uninit();
768 +               pisnd_spi_gpio_uninit();
769 +               pisnd_uninit_workqueues();
770 +               return ret;
771 +       }
772 +
773 +       if (pisnd_spi_has_more()) {
774 +               printd("data is available, scheduling from init\n");
775 +               pisnd_schedule_process(TASK_PROCESS);
776 +       }
777 +
778 +       return 0;
779 +}
780 +
781 +static void pisnd_spi_uninit(void)
782 +{
783 +       pisnd_uninit_workqueues();
784 +
785 +       spi_dev_put(pisnd_spi_device);
786 +       pisnd_spi_device = NULL;
787 +
788 +       pisnd_spi_gpio_irq_uninit();
789 +       pisnd_spi_gpio_uninit();
790 +}
791 +
792 +static void pisnd_spi_send(uint8_t val)
793 +{
794 +       kfifo_put(&spi_fifo_out, val);
795 +       printd("schedule from spi_send\n");
796 +       pisnd_schedule_process(TASK_PROCESS);
797 +}
798 +
799 +static uint8_t pisnd_spi_recv(uint8_t *buffer, uint8_t length)
800 +{
801 +       return kfifo_out(&spi_fifo_in, buffer, length);
802 +}
803 +
804 +static void pisnd_spi_set_callback(pisnd_spi_recv_cb cb, void *data)
805 +{
806 +       g_recvData = data;
807 +       g_recvCallback = cb;
808 +}
809 +
810 +static const char *pisnd_spi_get_serial(void)
811 +{
812 +       if (strlen(g_serial_num))
813 +               return g_serial_num;
814 +
815 +       return "";
816 +}
817 +
818 +static const char *pisnd_spi_get_id(void)
819 +{
820 +       if (strlen(g_id))
821 +               return g_id;
822 +
823 +       return "";
824 +}
825 +
826 +static const char *pisnd_spi_get_version(void)
827 +{
828 +       if (strlen(g_version))
829 +               return g_version;
830 +
831 +       return "";
832 +}
833 +
834 +static const struct of_device_id pisound_of_match[] = {
835 +       { .compatible = "blokaslabs,pisound", },
836 +       { .compatible = "blokaslabs,pisound-spi", },
837 +       {},
838 +};
839 +
840 +static struct gpio_desc *osr0, *osr1, *osr2;
841 +static struct gpio_desc *reset;
842 +static struct gpio_desc *button;
843 +
844 +static int pisnd_hw_params(
845 +       struct snd_pcm_substream *substream,
846 +       struct snd_pcm_hw_params *params
847 +       )
848 +{
849 +       printd("rate   = %d\n", params_rate(params));
850 +       printd("ch     = %d\n", params_channels(params));
851 +       printd("bits   = %u\n",
852 +               snd_pcm_format_physical_width(params_format(params)));
853 +       printd("format = %d\n", params_format(params));
854 +
855 +       gpiod_set_value(reset, false);
856 +
857 +       switch (params_rate(params)) {
858 +       case 48000:
859 +               gpiod_set_value(osr0, true);
860 +               gpiod_set_value(osr1, false);
861 +               gpiod_set_value(osr2, false);
862 +               break;
863 +       case 96000:
864 +               gpiod_set_value(osr0, true);
865 +               gpiod_set_value(osr1, true);
866 +               gpiod_set_value(osr2, false);
867 +               break;
868 +       case 192000:
869 +               gpiod_set_value(osr0, true);
870 +               gpiod_set_value(osr1, true);
871 +               gpiod_set_value(osr2, true);
872 +               break;
873 +       default:
874 +               printe("Unsupported rate %u!\n", params_rate(params));
875 +               return -EINVAL;
876 +       }
877 +
878 +       gpiod_set_value(reset, true);
879 +
880 +       return 0;
881 +}
882 +
883 +static unsigned int rates[3] = {
884 +       48000, 96000, 192000
885 +};
886 +
887 +static struct snd_pcm_hw_constraint_list constraints_rates = {
888 +       .count = ARRAY_SIZE(rates),
889 +       .list = rates,
890 +       .mask = 0,
891 +};
892 +
893 +static unsigned int sample_bits[] = {
894 +       24, 32
895 +};
896 +
897 +static struct snd_pcm_hw_constraint_list constraints_sample_bits = {
898 +       .count = ARRAY_SIZE(sample_bits),
899 +       .list = sample_bits,
900 +       .mask = 0,
901 +};
902 +
903 +static int pisnd_startup(struct snd_pcm_substream *substream)
904 +{
905 +       int err = snd_pcm_hw_constraint_list(
906 +               substream->runtime,
907 +               0,
908 +               SNDRV_PCM_HW_PARAM_RATE,
909 +               &constraints_rates
910 +               );
911 +
912 +       if (err < 0)
913 +               return err;
914 +
915 +       err = snd_pcm_hw_constraint_list(
916 +               substream->runtime,
917 +               0,
918 +               SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
919 +               &constraints_sample_bits
920 +               );
921 +
922 +       if (err < 0)
923 +               return err;
924 +
925 +       return 0;
926 +}
927 +
928 +static struct snd_soc_ops pisnd_ops = {
929 +       .startup = pisnd_startup,
930 +       .hw_params = pisnd_hw_params,
931 +};
932 +
933 +static struct snd_soc_dai_link pisnd_dai[] = {
934 +       {
935 +               .name           = "pisound",
936 +               .stream_name    = "pisound",
937 +               .cpu_dai_name   = "bcm2708-i2s.0",
938 +               .codec_dai_name = "snd-soc-dummy-dai",
939 +               .platform_name  = "bcm2708-i2s.0",
940 +               .codec_name     = "snd-soc-dummy",
941 +               .dai_fmt        =
942 +                       SND_SOC_DAIFMT_I2S |
943 +                       SND_SOC_DAIFMT_NB_NF |
944 +                       SND_SOC_DAIFMT_CBM_CFM,
945 +               .ops            = &pisnd_ops,
946 +       },
947 +};
948 +
949 +static int pisnd_card_probe(struct snd_soc_card *card)
950 +{
951 +       int err = pisnd_midi_init(card->snd_card);
952 +
953 +       if (err < 0)
954 +               printe("pisnd_midi_init failed: %d\n", err);
955 +
956 +       return err;
957 +}
958 +
959 +static int pisnd_card_remove(struct snd_soc_card *card)
960 +{
961 +       pisnd_midi_uninit();
962 +       return 0;
963 +}
964 +
965 +static struct snd_soc_card pisnd_card = {
966 +       .name         = "pisound",
967 +       .owner        = THIS_MODULE,
968 +       .dai_link     = pisnd_dai,
969 +       .num_links    = ARRAY_SIZE(pisnd_dai),
970 +       .probe        = pisnd_card_probe,
971 +       .remove       = pisnd_card_remove,
972 +};
973 +
974 +static int pisnd_init_gpio(struct device *dev)
975 +{
976 +       osr0 = gpiod_get_index(dev, "osr", 0, GPIOD_ASIS);
977 +       osr1 = gpiod_get_index(dev, "osr", 1, GPIOD_ASIS);
978 +       osr2 = gpiod_get_index(dev, "osr", 2, GPIOD_ASIS);
979 +
980 +       reset = gpiod_get_index(dev, "reset", 0, GPIOD_ASIS);
981 +
982 +       button = gpiod_get_index(dev, "button", 0, GPIOD_ASIS);
983 +
984 +       gpiod_direction_output(osr0,  1);
985 +       gpiod_direction_output(osr1,  1);
986 +       gpiod_direction_output(osr2,  1);
987 +       gpiod_direction_output(reset, 1);
988 +
989 +       gpiod_set_value(reset, false);
990 +       gpiod_set_value(osr0,   true);
991 +       gpiod_set_value(osr1,  false);
992 +       gpiod_set_value(osr2,  false);
993 +       gpiod_set_value(reset,  true);
994 +
995 +       gpiod_export(button, false);
996 +
997 +       return 0;
998 +}
999 +
1000 +static int pisnd_uninit_gpio(void)
1001 +{
1002 +       int i;
1003 +
1004 +       struct gpio_desc **gpios[] = {
1005 +               &osr0, &osr1, &osr2, &reset, &button,
1006 +       };
1007 +
1008 +       gpiod_unexport(button);
1009 +
1010 +       for (i = 0; i < ARRAY_SIZE(gpios); ++i) {
1011 +               if (*gpios[i] == NULL) {
1012 +                       printd("weird, GPIO[%d] is NULL already\n", i);
1013 +                       continue;
1014 +               }
1015 +
1016 +               gpiod_put(*gpios[i]);
1017 +               *gpios[i] = NULL;
1018 +       }
1019 +
1020 +       return 0;
1021 +}
1022 +
1023 +static struct kobject *pisnd_kobj;
1024 +
1025 +static ssize_t pisnd_serial_show(
1026 +       struct kobject *kobj,
1027 +       struct kobj_attribute *attr,
1028 +       char *buf
1029 +       )
1030 +{
1031 +       return sprintf(buf, "%s\n", pisnd_spi_get_serial());
1032 +}
1033 +
1034 +static ssize_t pisnd_id_show(
1035 +       struct kobject *kobj,
1036 +       struct kobj_attribute *attr,
1037 +       char *buf
1038 +       )
1039 +{
1040 +       return sprintf(buf, "%s\n", pisnd_spi_get_id());
1041 +}
1042 +
1043 +static ssize_t pisnd_version_show(
1044 +       struct kobject *kobj,
1045 +       struct kobj_attribute *attr,
1046 +       char *buf
1047 +       )
1048 +{
1049 +       return sprintf(buf, "%s\n", pisnd_spi_get_version());
1050 +}
1051 +
1052 +static struct kobj_attribute pisnd_serial_attribute =
1053 +       __ATTR(serial, 0644, pisnd_serial_show, NULL);
1054 +static struct kobj_attribute pisnd_id_attribute =
1055 +       __ATTR(id, 0644, pisnd_id_show, NULL);
1056 +static struct kobj_attribute pisnd_version_attribute =
1057 +       __ATTR(version, 0644, pisnd_version_show, NULL);
1058 +
1059 +static struct attribute *attrs[] = {
1060 +       &pisnd_serial_attribute.attr,
1061 +       &pisnd_id_attribute.attr,
1062 +       &pisnd_version_attribute.attr,
1063 +       NULL
1064 +};
1065 +
1066 +static struct attribute_group attr_group = { .attrs = attrs };
1067 +
1068 +static int pisnd_probe(struct platform_device *pdev)
1069 +{
1070 +       int ret = 0;
1071 +       int i;
1072 +
1073 +       ret = pisnd_spi_init(&pdev->dev);
1074 +       if (ret < 0) {
1075 +               printe("pisnd_spi_init failed: %d\n", ret);
1076 +               return ret;
1077 +       }
1078 +
1079 +       printi("Detected pisound card:\n");
1080 +       printi("\tSerial:  %s\n", pisnd_spi_get_serial());
1081 +       printi("\tVersion: %s\n", pisnd_spi_get_version());
1082 +       printi("\tId:      %s\n", pisnd_spi_get_id());
1083 +
1084 +       pisnd_kobj = kobject_create_and_add("pisound", kernel_kobj);
1085 +       if (!pisnd_kobj) {
1086 +               pisnd_spi_uninit();
1087 +               return -ENOMEM;
1088 +       }
1089 +
1090 +       ret = sysfs_create_group(pisnd_kobj, &attr_group);
1091 +       if (ret < 0) {
1092 +               pisnd_spi_uninit();
1093 +               kobject_put(pisnd_kobj);
1094 +               return -ENOMEM;
1095 +       }
1096 +
1097 +       pisnd_init_gpio(&pdev->dev);
1098 +       pisnd_card.dev = &pdev->dev;
1099 +
1100 +       if (pdev->dev.of_node) {
1101 +               struct device_node *i2s_node;
1102 +
1103 +               i2s_node = of_parse_phandle(
1104 +                       pdev->dev.of_node,
1105 +                       "i2s-controller",
1106 +                       0
1107 +                       );
1108 +
1109 +               for (i = 0; i < pisnd_card.num_links; ++i) {
1110 +                       struct snd_soc_dai_link *dai = &pisnd_dai[i];
1111 +
1112 +                       if (i2s_node) {
1113 +                               dai->cpu_dai_name = NULL;
1114 +                               dai->cpu_of_node = i2s_node;
1115 +                               dai->platform_name = NULL;
1116 +                               dai->platform_of_node = i2s_node;
1117 +                               dai->stream_name = pisnd_spi_get_serial();
1118 +                       }
1119 +               }
1120 +       }
1121 +
1122 +       ret = snd_soc_register_card(&pisnd_card);
1123 +
1124 +       if (ret < 0) {
1125 +               printe("snd_soc_register_card() failed: %d\n", ret);
1126 +               pisnd_uninit_gpio();
1127 +               kobject_put(pisnd_kobj);
1128 +               pisnd_spi_uninit();
1129 +       }
1130 +
1131 +       return ret;
1132 +}
1133 +
1134 +static int pisnd_remove(struct platform_device *pdev)
1135 +{
1136 +       printi("Unloading.\n");
1137 +
1138 +       if (pisnd_kobj) {
1139 +               kobject_put(pisnd_kobj);
1140 +               pisnd_kobj = NULL;
1141 +       }
1142 +
1143 +       pisnd_spi_uninit();
1144 +
1145 +       /* Turn off */
1146 +       gpiod_set_value(reset, false);
1147 +       pisnd_uninit_gpio();
1148 +
1149 +       return snd_soc_unregister_card(&pisnd_card);
1150 +}
1151 +
1152 +MODULE_DEVICE_TABLE(of, pisound_of_match);
1153 +
1154 +static struct platform_driver pisnd_driver = {
1155 +       .driver = {
1156 +               .name           = "snd-rpi-pisound",
1157 +               .owner          = THIS_MODULE,
1158 +               .of_match_table = pisound_of_match,
1159 +       },
1160 +       .probe              = pisnd_probe,
1161 +       .remove             = pisnd_remove,
1162 +};
1163 +
1164 +module_platform_driver(pisnd_driver);
1165 +
1166 +MODULE_AUTHOR("Giedrius Trainavicius <giedrius@blokas.io>");
1167 +MODULE_DESCRIPTION("ASoC Driver for pisound, http://blokas.io/pisound");
1168 +MODULE_LICENSE("GPL v2");