1 From ed992c4a8392b757e54b60bf2390015b72e3e947 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
6 Pisound dynamic overlay (#1760)
8 Restructuring pisound-overlay.dts, so it can be loaded and unloaded dynamically using dtoverlay.
10 Print a logline when the kernel module is removed.
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
21 Add missing SND_PISOUND selects dependency to SND_RAWMIDI
23 Without it the Pisound module fails to compile.
24 See https://github.com/raspberrypi/linux/issues/2366
26 Updates for Pisound module code:
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
34 Signed-off-by: Giedrius Trainavicius <giedrius@blokas.io>
36 Fixing memset call in pisound.c
38 Signed-off-by: Giedrius Trainavicius <giedrius@blokas.io>
40 Fix for Pisound's MIDI Input getting blocked for a while in rare cases.
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
46 Signed-off-by: Giedrius Trainavicius <giedrius@blokas.io>
48 Fix for Pisound kernel module in Real Time kernel configuration.
50 When handler of data_available interrupt is fired, queue_work ends up
51 getting called and it can block on a spin lock which is not allowed in
52 interrupt context. The fix was to run the handler from a thread context
55 Pisound: Remove spinlock usage around spi_sync
57 ASoC: pisound: use modern dai_link style
59 Signed-off-by: Hui Wang <hui.wang@canonical.com>
61 ASoC: pisound: fix the parameter for spi_device_match
63 Signed-off-by: Hui Wang <hui.wang@canonical.com>
65 .../devicetree/bindings/vendor-prefixes.txt | 463 +++++++
66 .../devicetree/bindings/vendor-prefixes.yaml | 2 +
67 sound/soc/bcm/pisound.c | 1201 +++++++++++++++++
68 3 files changed, 1666 insertions(+)
69 create mode 100644 Documentation/devicetree/bindings/vendor-prefixes.txt
70 create mode 100644 sound/soc/bcm/pisound.c
73 +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
75 +Device tree binding vendor prefix registry. Keep list in alphabetical order.
77 +This isn't an exhaustive list, but you should add new prefixes to it before
78 +using them to avoid name-space collisions.
80 +abilis Abilis Systems
81 +abracon Abracon Corporation
82 +actions Actions Semiconductor Co., Ltd.
83 +active-semi Active-Semi International Inc
84 +ad Avionic Design GmbH
85 +adafruit Adafruit Industries, LLC
86 +adapteva Adapteva, Inc.
87 +adaptrum Adaptrum, Inc.
89 +adi Analog Devices, Inc.
90 +advantech Advantech Corporation
91 +aeroflexgaisler Aeroflex Gaisler AB
94 +allwinner Allwinner Technology Co., Ltd.
95 +alphascale AlphaScale Integrated Circuits Systems, Inc.
97 +amarula Amarula Solutions
98 +amazon Amazon.com, Inc.
99 +amcc Applied Micro Circuits Corporation (APM, formally AMCC)
100 +amd Advanced Micro Devices (AMD), Inc.
101 +amediatech Shenzhen Amediatech Technology Co., Ltd
102 +amlogic Amlogic, Inc.
103 +ampire Ampire Co., Ltd.
105 +amstaos AMS-Taos Inc.
106 +analogix Analogix Semiconductor, Inc.
107 +andestech Andes Technology Corporation
108 +apm Applied Micro Circuits Corporation (APM)
109 +aptina Aptina Imaging
110 +arasan Arasan Chip Systems
111 +archermind ArcherMind Technology (Nanjing) Co., Ltd.
113 +aries Aries Embedded GmbH
115 +armadeus ARMadeus Systems SARL
116 +arrow Arrow Electronics
117 +artesyn Artesyn Embedded Technologies Inc.
118 +asahi-kasei Asahi Kasei Corp.
119 +aspeed ASPEED Technology Inc.
120 +asus AsusTek Computer Inc.
121 +atlas Atlas Scientific LLC
122 +atmel Atmel Corporation
123 +auo AU Optronics Corporation
124 +auvidea Auvidea GmbH
125 +avago Avago Technologies
126 +avia avia semiconductor
127 +avic Shanghai AVIC Optoelectronics Co., Ltd.
129 +axentia Axentia Technologies AB
130 +axis Axis Communications AB
131 +bananapi BIPAI KEJI LIMITED
132 +bhf Beckhoff Automation GmbH & Co. KG
133 +bitmain Bitmain Technologies
134 +blokaslabs Vilniaus Blokas UAB
135 +boe BOE Technology Group Co., Ltd.
136 +bosch Bosch Sensortec GmbH
137 +boundary Boundary Devices Inc.
138 +brcm Broadcom Corporation
139 +buffalo Buffalo, Inc.
140 +bticino Bticino International
142 +capella Capella Microsystems, Inc
143 +cascoda Cascoda, Ltd.
144 +catalyst Catalyst Semiconductor, Inc.
146 +cdns Cadence Design Systems Inc.
147 +cdtech CDTech(H.K.) Electronics Limited
149 +chipidea Chipidea, Inc
152 +chrp Common Hardware Reference Platform
153 +chunghwa Chunghwa Picture Tubes Ltd.
154 +ciaa Computadora Industrial Abierta Argentina
155 +cirrus Cirrus Logic, Inc.
156 +cloudengines Cloud Engines, Inc.
157 +cnm Chips&Media, Inc.
158 +cnxt Conexant Systems, Inc.
159 +compulab CompuLab Ltd.
160 +cortina Cortina Systems, Inc.
161 +cosmic Cosmic Circuits
162 +crane Crane Connectivity Solutions
163 +creative Creative Technology Ltd
164 +crystalfontz Crystalfontz America, Inc.
165 +csky Hangzhou C-SKY Microsystems Co., Ltd
166 +cubietech Cubietech, Ltd.
167 +cypress Cypress Semiconductor Corporation
168 +cznic CZ.NIC, z.s.p.o.
169 +dallas Maxim Integrated Products (formerly Dallas Semiconductor)
170 +dataimage DataImage, Inc.
171 +davicom DAVICOM Semiconductor, Inc.
172 +delta Delta Electronics, Inc.
173 +denx Denx Software Engineering
174 +devantech Devantech, Ltd.
175 +dh DH electronics GmbH
176 +digi Digi International Inc.
177 +digilent Diglent, Inc.
178 +dioo Dioo Microcircuit Co., Ltd
179 +dlc DLC Display Co., Ltd.
180 +dlg Dialog Semiconductor
181 +dlink D-Link Corporation
183 +domintech Domintech Co., Ltd.
184 +dongwoon Dongwoon Anatech
185 +dptechnics DPTechnics
186 +dragino Dragino Technology Co., Limited
187 +ea Embedded Artists AB
188 +ebs-systart EBS-SYSTART GmbH
190 +eckelmann Eckelmann AG
191 +edt Emerging Display Technologies
192 +eeti eGalax_eMPIA Technology Inc
193 +elan Elan Microelectronic Corp.
195 +embest Shenzhen Embest Technology Co., Ltd.
197 +emmicro EM Microelectronic
198 +emtrion emtrion GmbH
199 +endless Endless Mobile, Inc.
200 +energymicro Silicon Laboratories (formerly Energy Micro AS)
201 +engicam Engicam S.r.l.
203 +epfl Ecole Polytechnique Fédérale de Lausanne
204 +epson Seiko Epson Corp.
205 +est ESTeem Wireless Modems
206 +ettus NI Ettus Research
207 +eukrea Eukréa Electromatique
208 +everest Everest Semiconductor Co. Ltd.
209 +everspin Everspin Technologies, Inc.
210 +exar Exar Corporation
212 +ezchip EZchip Semiconductor
214 +fairphone Fairphone B.V.
215 +faraday Faraday Technology Corporation
217 +fcs Fairchild Semiconductor
218 +feiyang Shenzhen Fly Young Technology Co.,LTD.
220 +focaltech FocalTech Systems Co.,Ltd
221 +friendlyarm Guangzhou FriendlyARM Computer Tech Co., Ltd
222 +fsl Freescale Semiconductor
223 +fujitsu Fujitsu Ltd.
224 +gateworks Gateworks Corporation
225 +gcw Game Consoles Worldwide
226 +ge General Electric Company
227 +geekbuying GeekBuying
228 +gef GE Fanuc Intelligent Platforms Embedded Systems, Inc.
229 +GEFanuc GE Fanuc Intelligent Platforms Embedded Systems, Inc.
230 +geniatech Geniatech, Inc.
231 +giantec Giantec Semiconductor, Inc.
232 +giantplus Giantplus Technology Co., Ltd.
233 +globalscale Globalscale Technologies, Inc.
234 +globaltop GlobalTop Technology, Inc.
235 +gmt Global Mixed-mode Technology, Inc.
236 +goodix Shenzhen Huiding Technology Co., Ltd.
240 +gumstix Gumstix, Inc.
241 +gw Gateworks Corporation
242 +hannstar HannStar Display Corporation
243 +haoyu Haoyu Microelectronic Co. Ltd.
244 +hardkernel Hardkernel Co., Ltd
246 +himax Himax Technologies, Inc.
247 +hisilicon Hisilicon Limited.
249 +hitex Hitex Development Tools
250 +holt Holt Integrated Circuits, Inc.
253 +holtek Holtek Semiconductor, Inc.
254 +hwacom HwaCom Systems Inc.
256 +ibm International Business Machines (IBM)
257 +icplus IC Plus Corp.
258 +idt Integrated Device Technologies, Inc.
259 +ifi Ingenieurburo Fur Ic-Technologie (I/F/I)
260 +ilitek ILI Technology Corporation (ILITEK)
261 +img Imagination Technologies Ltd.
262 +infineon Infineon Technologies
263 +inforce Inforce Computing
264 +ingenic Ingenic Semiconductor
265 +innolux Innolux Corporation
266 +inside-secure INSIDE Secure
267 +intel Intel Corporation
268 +intercontrol Inter Control Group
269 +invensense InvenSense Inc.
270 +inversepath Inverse Path
271 +iom Iomega Corporation
274 +issi Integrated Silicon Solutions Inc.
275 +itead ITEAD Intelligent Systems Co.Ltd
276 +iwave iWave Systems Technologies Pvt. Ltd.
277 +jdi Japan Display Inc.
278 +jedec JEDEC Solid State Technology Association
279 +jianda Jiandangjing Technology Co., Ltd.
280 +karo Ka-Ro electronics GmbH
281 +keithkoep Keith & Koep GmbH
282 +keymile Keymile GmbH
284 +kiebackpeter Kieback & Peter GmbH
285 +kinetic Kinetic Technologies
286 +kingdisplay King & Display Technology Co., Ltd.
287 +kingnovel Kingnovel Technology Co., Ltd.
288 +koe Kaohsiung Opto-Electronics Inc.
289 +kosagi Sutajio Ko-Usagi PTE Ltd.
290 +kyo Kyocera Corporation
293 +lantiq Lantiq Semiconductor
294 +lattice Lattice Semiconductor
295 +lego LEGO Systems A/S
296 +lemaker Shenzhen LeMaker Technology Co., Ltd.
297 +lenovo Lenovo Group Ltd.
299 +libretech Shenzhen Libre Technology Co., Ltd
301 +linaro Linaro Limited
302 +linksys Belkin International, Inc. (Linksys)
303 +linux Linux-specific binding
304 +linx Linx Technologies
305 +lltc Linear Technology Corporation
306 +logicpd Logic PD, Inc.
307 +lsi LSI Corp. (LSI Logic)
308 +lwn Liebherr-Werk Nenzing GmbH
309 +macnica Macnica Americas
310 +marvell Marvell Technology Group Ltd.
311 +maxim Maxim Integrated Products
314 +meas Measurement Specialties
315 +mediatek MediaTek Inc.
317 +mele Shenzhen MeLE Digital Technology Ltd.
318 +melexis Melexis N.V.
320 +mellanox Mellanox Technologies
322 +merrii Merrii Technology Co., Ltd.
324 +microchip Microchip Technology Inc.
325 +microcrystal Micro Crystal AG
326 +micron Micron Technology Inc.
327 +mikroe MikroElektronika d.o.o.
328 +minix MINIX Technology Ltd.
329 +miramems MiraMEMS Sensing Technology Co., Ltd.
330 +mitsubishi Mitsubishi Electric Corporation
331 +mosaixtech Mosaix Technologies, Inc.
332 +motorola Motorola, Inc.
335 +mqmaker mqmaker Inc.
336 +mscc Microsemi Corporation
337 +msi Micro-Star International Co. Ltd.
338 +mti Imagination Technologies Ltd. (formerly MIPS Technologies Inc.)
339 +multi-inno Multi-Inno Technology Co.,Ltd
340 +mundoreader Mundo Reader S.L.
341 +murata Murata Manufacturing Co., Ltd.
342 +mxicy Macronix International Co., Ltd.
343 +myir MYIR Tech Limited
344 +national National Semiconductor
345 +nec NEC LCD Technologies, Ltd.
346 +neonode Neonode Inc.
348 +netlogic Broadcom Corporation (formerly NetLogic Microsystems)
350 +netxeon Shenzhen Netxeon Technology CO., LTD
352 +nextthing Next Thing Co.
353 +newhaven Newhaven Display International
354 +ni National Instruments
356 +nlt NLT Technologies, Ltd.
358 +nordic Nordic Semiconductor
359 +novtech NovTech, Inc.
361 +nuvoton Nuvoton Technology Corporation
362 +nvd New Vision Display
364 +nxp NXP Semiconductors
365 +okaya Okaya Electric America, Inc.
366 +oki Oki Electric Industry Co., Ltd.
368 +olpc One Laptop Per Child
369 +onion Onion Corporation
370 +onnn ON Semiconductor Corp.
371 +ontat On Tat Industrial Company
372 +opalkelly Opal Kelly Incorporated
373 +opencores OpenCores.org
374 +openrisc OpenRISC.io
376 +oranth Shenzhen Oranth Technology Co., Ltd.
377 +ORCL Oracle Corporation
378 +orisetech Orise Technology
379 +ortustech Ortus Technology Co., Ltd.
380 +ovti OmniVision Technologies
381 +oxsemi Oxford Semiconductor, Ltd.
382 +panasonic Panasonic Corporation
383 +parade Parade Technologies Inc.
384 +pda Precision Design Associates, Inc.
385 +pericom Pericom Technology Inc.
386 +pervasive Pervasive Displays, Inc.
387 +phicomm PHICOMM Co., Ltd.
388 +phytec PHYTEC Messtechnik GmbH
389 +picochip Picochip Ltd
391 +pixcir PIXCIR MICROELECTRONICS Co., Ltd
392 +plantower Plantower Co., Ltd
393 +plathome Plat'Home Co., Ltd.
395 +plx Broadcom Corporation (formerly PLX Technology)
396 +pni PNI Sensor Corporation
397 +portwell Portwell Inc.
398 +poslab Poslab Technology Co., Ltd.
399 +powervr PowerVR (deprecated, use img)
400 +probox2 PROBOX2 (by W2COMP Co., Ltd.)
401 +pulsedlight PulsedLight, Inc
402 +qca Qualcomm Atheros, Inc.
403 +qcom Qualcomm Technologies, Inc
404 +qemu QEMU, a generic and open source machine emulator and virtualizer
406 +qiaodian QiaoDian XianShi Corporation
407 +qnap QNAP Systems, Inc.
409 +raidsonic RaidSonic Technology GmbH
410 +ralink Mediatek/Ralink Technology Corp.
411 +ramtron Ramtron International
412 +raspberrypi Raspberry Pi Foundation
413 +raydium Raydium Semiconductor Corp.
414 +rda Unisoc Communications, Inc.
415 +realtek Realtek Semiconductor Corp.
416 +renesas Renesas Electronics Corporation
417 +richtek Richtek Technology Corporation
418 +ricoh Ricoh Co. Ltd.
419 +rikomagic Rikomagic Tech Corp. Ltd
420 +riscv RISC-V Foundation
421 +rockchip Fuzhou Rockchip Electronics Co., Ltd
422 +rohm ROHM Semiconductor Co., Ltd
423 +roofull Shenzhen Roofull Technology Co, Ltd
424 +samsung Samsung Semiconductor
425 +samtec Samtec/Softing company
426 +sancloud Sancloud Ltd
427 +sandisk Sandisk Corporation
428 +sbs Smart Battery System
430 +seagate Seagate Technology PLC
431 +semtech Semtech Corporation
432 +sensirion Sensirion AG
433 +sff Small Form Factor Committee
434 +sgd Solomon Goldentek Display Corporation
436 +sharp Sharp Corporation
437 +shimafuji Shimafuji Electric, Inc.
438 +si-en Si-En Technology Ltd.
440 +sigma Sigma Designs, Inc.
441 +sii Seiko Instruments, Inc.
443 +silabs Silicon Laboratories
445 +silergy Silergy Corp.
446 +siliconmitus Silicon Mitus, Inc.
448 +sirf SiRF Technology, Inc.
449 +sis Silicon Integrated Systems Corp.
450 +sitronix Sitronix Technology Corporation
451 +skyworks Skyworks Solutions, Inc.
452 +smsc Standard Microsystems Corporation
454 +socionext Socionext Inc.
456 +solomon Solomon Systech Limited
457 +sony Sony Corporation
458 +spansion Spansion Inc.
459 +sprd Spreadtrum Communications Inc.
460 +sst Silicon Storage Technology, Inc.
461 +st STMicroelectronics
462 +starry Starry Electronic Technology (ShenZhen) Co., LTD
465 +stericsson ST-Ericsson
466 +summit Summit microelectronics
467 +sunchip Shenzhen Sunchip Technology Co., Ltd
468 +SUNW Sun Microsystems, Inc
469 +swir Sierra Wireless
471 +synology Synology, Inc.
472 +tbs TBS Technologies
473 +tbs-biometrics Touchless Biometric Systems AG
474 +tcg Trusted Computing Group
475 +tcl Toby Churchill Ltd.
476 +technexion TechNexion
477 +technologic Technologic Systems
478 +tempo Tempo Semiconductor
479 +techstar Shenzhen Techstar Electronics Co., Ltd.
480 +terasic Terasic Inc.
481 +thine THine Electronics, Inc.
482 +ti Texas Instruments
483 +tianma Tianma Micro-electronics Co., Ltd.
484 +tlm Trusted Logic Mobility
485 +tmt Tecon Microprocessor Technologies, LLC.
488 +toshiba Toshiba Corporation
491 +tplink TP-LINK Technologies Co., Ltd.
495 +truly Truly Semiconductors Limited
496 +tsd Theobroma Systems Design und Consulting GmbH
497 +tyan Tyan Computer Corporation
499 +ucrobotics uCRobotics
500 +ubnt Ubiquiti Networks
502 +uniwest United Western Technologies Corp (UniWest)
503 +upisemi uPI Semiconductor Corp.
504 +urt United Radiant Technology Corporation
505 +usi Universal Scientific Industrial Co., Ltd.
508 +variscite Variscite Ltd.
509 +via VIA Technologies, Inc.
510 +virtio Virtual I/O Device Specification, developed by the OASIS consortium
511 +vishay Vishay Intertechnology, Inc
512 +vitesse Vitesse Semiconductor Corporation
513 +vivante Vivante Corporation
514 +vocore VoCore Studio
515 +voipac Voipac Technologies s.r.o.
516 +vot Vision Optical Technology Co., Ltd.
517 +wd Western Digital Corp.
518 +wetek WeTek Electronics, limited.
520 +whwave Shenzhen whwave Electronics, Inc.
522 +winbond Winbond Electronics corp.
523 +winstar Winstar Display Corp.
524 +wlf Wolfson Microelectronics
525 +wm Wondermedia Technologies, Inc.
527 +xes Extreme Engineering Solutions (X-ES)
528 +xillybus Xillybus Ltd.
530 +xunlong Shenzhen Xunlong Software CO.,Limited
531 +ysoft Y Soft Corporation a.s.
532 +zarlink Zarlink Semiconductor
533 +zeitec ZEITEC Semiconductor Co., LTD.
534 +zidoo Shenzhen Zidoo Technology Co., Ltd.
535 +zii Zodiac Inflight Innovations
537 +zyxel ZyXEL Communications Corp.
538 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
539 +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
540 @@ -143,6 +143,8 @@ patternProperties:
541 description: Beckhoff Automation GmbH & Co. KG
543 description: Bitmain Technologies
545 + description: Vilniaus Blokas UAB
547 description: BOE Technology Group Co., Ltd.
550 +++ b/sound/soc/bcm/pisound.c
553 + * Pisound Linux kernel module.
554 + * Copyright (C) 2016-2019 Vilniaus Blokas UAB, https://blokas.io/pisound
556 + * This program is free software; you can redistribute it and/or
557 + * modify it under the terms of the GNU General Public License
558 + * as published by the Free Software Foundation; version 2 of the
561 + * This program is distributed in the hope that it will be useful,
562 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
563 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
564 + * GNU General Public License for more details.
566 + * You should have received a copy of the GNU General Public License
567 + * along with this program; if not, write to the Free Software
568 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
569 + * MA 02110-1301, USA.
572 +#include <linux/init.h>
573 +#include <linux/module.h>
574 +#include <linux/platform_device.h>
575 +#include <linux/gpio.h>
576 +#include <linux/kobject.h>
577 +#include <linux/sysfs.h>
578 +#include <linux/delay.h>
579 +#include <linux/spi/spi.h>
580 +#include <linux/interrupt.h>
581 +#include <linux/kfifo.h>
582 +#include <linux/jiffies.h>
584 +#include <sound/core.h>
585 +#include <sound/pcm.h>
586 +#include <sound/pcm_params.h>
587 +#include <sound/soc.h>
588 +#include <sound/jack.h>
589 +#include <sound/rawmidi.h>
590 +#include <sound/asequencer.h>
591 +#include <sound/control.h>
593 +static int pisnd_spi_init(struct device *dev);
594 +static void pisnd_spi_uninit(void);
596 +static void pisnd_spi_flush(void);
597 +static void pisnd_spi_start(void);
598 +static uint8_t pisnd_spi_recv(uint8_t *buffer, uint8_t length);
600 +typedef void (*pisnd_spi_recv_cb)(void *data);
601 +static void pisnd_spi_set_callback(pisnd_spi_recv_cb cb, void *data);
603 +static const char *pisnd_spi_get_serial(void);
604 +static const char *pisnd_spi_get_id(void);
605 +static const char *pisnd_spi_get_version(void);
607 +static int pisnd_midi_init(struct snd_card *card);
608 +static void pisnd_midi_uninit(void);
614 +static void pisnd_schedule_process(enum task_e task);
616 +#define PISOUND_LOG_PREFIX "pisound: "
618 +#ifdef PISOUND_DEBUG
619 +# define printd(...) pr_alert(PISOUND_LOG_PREFIX __VA_ARGS__)
621 +# define printd(...) do {} while (0)
624 +#define printe(...) pr_err(PISOUND_LOG_PREFIX __VA_ARGS__)
625 +#define printi(...) pr_info(PISOUND_LOG_PREFIX __VA_ARGS__)
627 +static struct snd_rawmidi *g_rmidi;
628 +static struct snd_rawmidi_substream *g_midi_output_substream;
630 +static int pisnd_output_open(struct snd_rawmidi_substream *substream)
632 + g_midi_output_substream = substream;
636 +static int pisnd_output_close(struct snd_rawmidi_substream *substream)
638 + g_midi_output_substream = NULL;
642 +static void pisnd_output_trigger(
643 + struct snd_rawmidi_substream *substream,
647 + if (substream != g_midi_output_substream) {
648 + printe("MIDI output trigger called for an unexpected stream!");
658 +static void pisnd_output_drain(struct snd_rawmidi_substream *substream)
663 +static int pisnd_input_open(struct snd_rawmidi_substream *substream)
668 +static int pisnd_input_close(struct snd_rawmidi_substream *substream)
673 +static void pisnd_midi_recv_callback(void *substream)
678 + while ((n = pisnd_spi_recv(data, sizeof(data)))) {
679 + int res = snd_rawmidi_receive(substream, data, n);
681 + printd("midi recv %u bytes, res = %d\n", n, res);
685 +static void pisnd_input_trigger(struct snd_rawmidi_substream *substream, int up)
688 + pisnd_spi_set_callback(pisnd_midi_recv_callback, substream);
689 + pisnd_schedule_process(TASK_PROCESS);
691 + pisnd_spi_set_callback(NULL, NULL);
695 +static struct snd_rawmidi_ops pisnd_output_ops = {
696 + .open = pisnd_output_open,
697 + .close = pisnd_output_close,
698 + .trigger = pisnd_output_trigger,
699 + .drain = pisnd_output_drain,
702 +static struct snd_rawmidi_ops pisnd_input_ops = {
703 + .open = pisnd_input_open,
704 + .close = pisnd_input_close,
705 + .trigger = pisnd_input_trigger,
708 +static void pisnd_get_port_info(
709 + struct snd_rawmidi *rmidi,
711 + struct snd_seq_port_info *seq_port_info
714 + seq_port_info->type =
715 + SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC |
716 + SNDRV_SEQ_PORT_TYPE_HARDWARE |
717 + SNDRV_SEQ_PORT_TYPE_PORT;
718 + seq_port_info->midi_voices = 0;
721 +static struct snd_rawmidi_global_ops pisnd_global_ops = {
722 + .get_port_info = pisnd_get_port_info,
725 +static int pisnd_midi_init(struct snd_card *card)
729 + g_midi_output_substream = NULL;
731 + err = snd_rawmidi_new(card, "pisound MIDI", 0, 1, 1, &g_rmidi);
734 + printe("snd_rawmidi_new failed: %d\n", err);
738 + strcpy(g_rmidi->name, "pisound MIDI ");
739 + strcat(g_rmidi->name, pisnd_spi_get_serial());
741 + g_rmidi->info_flags =
742 + SNDRV_RAWMIDI_INFO_OUTPUT |
743 + SNDRV_RAWMIDI_INFO_INPUT |
744 + SNDRV_RAWMIDI_INFO_DUPLEX;
746 + g_rmidi->ops = &pisnd_global_ops;
748 + g_rmidi->private_data = (void *)0;
750 + snd_rawmidi_set_ops(
752 + SNDRV_RAWMIDI_STREAM_OUTPUT,
756 + snd_rawmidi_set_ops(
758 + SNDRV_RAWMIDI_STREAM_INPUT,
765 +static void pisnd_midi_uninit(void)
769 +static void *g_recvData;
770 +static pisnd_spi_recv_cb g_recvCallback;
772 +#define FIFO_SIZE 4096
774 +static char g_serial_num[11];
775 +static char g_id[25];
776 +static char g_version[5];
778 +static uint8_t g_ledFlashDuration;
779 +static bool g_ledFlashDurationChanged;
781 +DEFINE_KFIFO(spi_fifo_in, uint8_t, FIFO_SIZE);
782 +DEFINE_KFIFO(spi_fifo_out, uint8_t, FIFO_SIZE);
784 +static struct gpio_desc *data_available;
785 +static struct gpio_desc *spi_reset;
787 +static struct spi_device *pisnd_spi_device;
789 +static struct workqueue_struct *pisnd_workqueue;
790 +static struct work_struct pisnd_work_process;
792 +static void pisnd_work_handler(struct work_struct *work);
794 +static void spi_transfer(const uint8_t *txbuf, uint8_t *rxbuf, int len);
795 +static uint16_t spi_transfer16(uint16_t val);
797 +static int pisnd_init_workqueues(void)
799 + pisnd_workqueue = create_singlethread_workqueue("pisnd_workqueue");
800 + INIT_WORK(&pisnd_work_process, pisnd_work_handler);
805 +static void pisnd_uninit_workqueues(void)
807 + flush_workqueue(pisnd_workqueue);
808 + destroy_workqueue(pisnd_workqueue);
810 + pisnd_workqueue = NULL;
813 +static bool pisnd_spi_has_more(void)
815 + return gpiod_get_value(data_available);
818 +static void pisnd_schedule_process(enum task_e task)
820 + if (pisnd_spi_device != NULL &&
821 + pisnd_workqueue != NULL &&
822 + !work_pending(&pisnd_work_process)
824 + printd("schedule: has more = %d\n", pisnd_spi_has_more());
825 + if (task == TASK_PROCESS)
826 + queue_work(pisnd_workqueue, &pisnd_work_process);
830 +static irqreturn_t data_available_interrupt_handler(int irq, void *dev_id)
832 + if (irq == gpiod_to_irq(data_available) && pisnd_spi_has_more()) {
833 + printd("schedule from irq\n");
834 + pisnd_schedule_process(TASK_PROCESS);
837 + return IRQ_HANDLED;
840 +static uint16_t spi_transfer16(uint16_t val)
845 + if (!pisnd_spi_device) {
846 + printe("pisnd_spi_device null, returning\n");
850 + txbuf[0] = val >> 8;
851 + txbuf[1] = val & 0xff;
853 + spi_transfer(txbuf, rxbuf, sizeof(txbuf));
855 + printd("received: %02x%02x\n", rxbuf[0], rxbuf[1]);
857 + return (rxbuf[0] << 8) | rxbuf[1];
860 +static void spi_transfer(const uint8_t *txbuf, uint8_t *rxbuf, int len)
863 + struct spi_transfer transfer;
864 + struct spi_message msg;
866 + memset(rxbuf, 0, len);
868 + if (!pisnd_spi_device) {
869 + printe("pisnd_spi_device null, returning\n");
873 + spi_message_init(&msg);
875 + memset(&transfer, 0, sizeof(transfer));
877 + transfer.tx_buf = txbuf;
878 + transfer.rx_buf = rxbuf;
879 + transfer.len = len;
880 + transfer.speed_hz = 100000;
881 + transfer.delay_usecs = 10;
882 + spi_message_add_tail(&transfer, &msg);
884 + err = spi_sync(pisnd_spi_device, &msg);
887 + printe("spi_sync error %d\n", err);
891 + printd("hasMore %d\n", pisnd_spi_has_more());
894 +static int spi_read_bytes(char *dst, size_t length, uint8_t *bytesRead)
900 + memset(dst, 0, length);
903 + rx = spi_transfer16(0);
912 + for (i = 0; i < size; ++i) {
913 + rx = spi_transfer16(0);
917 + dst[i] = rx & 0xff;
925 +static int spi_device_match(struct device *dev, const void *data)
927 + struct spi_device *spi = container_of(dev, struct spi_device, dev);
929 + printd(" %s %s %dkHz %d bits mode=0x%02X\n",
930 + spi->modalias, dev_name(dev), spi->max_speed_hz/1000,
931 + spi->bits_per_word, spi->mode);
933 + if (strcmp("pisound-spi", spi->modalias) == 0) {
934 + printi("\tFound!\n");
938 + printe("\tNot found!\n");
942 +static struct spi_device *pisnd_spi_find_device(void)
944 + struct device *dev;
946 + printi("Searching for spi device...\n");
947 + dev = bus_find_device(&spi_bus_type, NULL, NULL, spi_device_match);
949 + return container_of(dev, struct spi_device, dev);
954 +static void pisnd_work_handler(struct work_struct *work)
956 + enum { TRANSFER_SIZE = 4 };
957 + enum { PISOUND_OUTPUT_BUFFER_SIZE = 128 };
958 + enum { MIDI_BYTES_PER_SECOND = 3125 };
959 + int out_buffer_used = 0;
962 + uint8_t txbuf[TRANSFER_SIZE];
963 + uint8_t rxbuf[TRANSFER_SIZE];
964 + uint8_t midibuf[TRANSFER_SIZE];
968 + unsigned long last_transfer_at = jiffies;
970 + if (work == &pisnd_work_process) {
971 + if (pisnd_spi_device == NULL)
975 + if (g_midi_output_substream &&
976 + kfifo_avail(&spi_fifo_out) >= sizeof(midibuf)) {
978 + n = snd_rawmidi_transmit_peek(
979 + g_midi_output_substream,
980 + midibuf, sizeof(midibuf)
984 + for (i = 0; i < n; ++i)
989 + snd_rawmidi_transmit_ack(
990 + g_midi_output_substream,
997 + memset(txbuf, 0, sizeof(txbuf));
998 + for (i = 0; i < sizeof(txbuf) &&
999 + out_buffer_used < PISOUND_OUTPUT_BUFFER_SIZE;
1004 + if (g_ledFlashDurationChanged) {
1005 + txbuf[i+0] = 0xf0;
1006 + txbuf[i+1] = g_ledFlashDuration;
1007 + g_ledFlashDuration = 0;
1008 + g_ledFlashDurationChanged = false;
1009 + } else if (kfifo_get(&spi_fifo_out, &val)) {
1010 + txbuf[i+0] = 0x0f;
1012 + ++out_buffer_used;
1016 + spi_transfer(txbuf, rxbuf, sizeof(txbuf));
1017 + /* Estimate the Pisound's MIDI output buffer usage, so
1018 + * that we don't overflow it. Space in the buffer should
1019 + * be becoming available at the UART MIDI byte transfer
1023 + out_buffer_used -=
1024 + (MIDI_BYTES_PER_SECOND / HZ) /
1025 + (now - last_transfer_at);
1026 + if (out_buffer_used < 0)
1027 + out_buffer_used = 0;
1028 + last_transfer_at = now;
1030 + for (i = 0; i < sizeof(rxbuf); i += 2) {
1032 + kfifo_put(&spi_fifo_in, rxbuf[i+1]);
1033 + if (kfifo_len(&spi_fifo_in) > 16 &&
1035 + g_recvCallback(g_recvData);
1040 + || !kfifo_is_empty(&spi_fifo_out)
1041 + || pisnd_spi_has_more()
1042 + || g_ledFlashDurationChanged
1045 + if (!kfifo_is_empty(&spi_fifo_in) && g_recvCallback)
1046 + g_recvCallback(g_recvData);
1050 +static int pisnd_spi_gpio_init(struct device *dev)
1052 + spi_reset = gpiod_get_index(dev, "reset", 1, GPIOD_ASIS);
1053 + data_available = gpiod_get_index(dev, "data_available", 0, GPIOD_ASIS);
1055 + gpiod_direction_output(spi_reset, 1);
1056 + gpiod_direction_input(data_available);
1058 + /* Reset the slave. */
1059 + gpiod_set_value(spi_reset, false);
1061 + gpiod_set_value(spi_reset, true);
1063 + /* Give time for spi slave to start. */
1069 +static void pisnd_spi_gpio_uninit(void)
1071 + gpiod_set_value(spi_reset, false);
1072 + gpiod_put(spi_reset);
1075 + gpiod_put(data_available);
1076 + data_available = NULL;
1079 +static int pisnd_spi_gpio_irq_init(struct device *dev)
1081 + return request_threaded_irq(
1082 + gpiod_to_irq(data_available), NULL,
1083 + data_available_interrupt_handler,
1084 + IRQF_TIMER | IRQF_TRIGGER_RISING | IRQF_ONESHOT,
1085 + "data_available_int",
1090 +static void pisnd_spi_gpio_irq_uninit(void)
1092 + free_irq(gpiod_to_irq(data_available), NULL);
1095 +static int spi_read_info(void)
1106 + memset(g_serial_num, 0, sizeof(g_serial_num));
1107 + memset(g_version, 0, sizeof(g_version));
1108 + memset(g_id, 0, sizeof(g_id));
1110 + tmp = spi_transfer16(0);
1115 + count = tmp & 0xff;
1117 + for (i = 0; i < count; ++i) {
1118 + memset(buffer, 0, sizeof(buffer));
1119 + ret = spi_read_bytes(buffer, sizeof(buffer)-1, &n);
1131 + sizeof(g_version),
1138 + if (n >= sizeof(g_serial_num))
1141 + memcpy(g_serial_num, buffer, sizeof(g_serial_num));
1145 + if (n >= sizeof(g_id))
1149 + for (j = 0; j < n; ++j)
1150 + p += sprintf(p, "%02x", buffer[j]);
1161 +static int pisnd_spi_init(struct device *dev)
1164 + struct spi_device *spi;
1166 + memset(g_serial_num, 0, sizeof(g_serial_num));
1167 + memset(g_id, 0, sizeof(g_id));
1168 + memset(g_version, 0, sizeof(g_version));
1170 + spi = pisnd_spi_find_device();
1172 + if (spi != NULL) {
1173 + printd("initializing spi!\n");
1174 + pisnd_spi_device = spi;
1175 + ret = spi_setup(pisnd_spi_device);
1177 + printe("SPI device not found, deferring!\n");
1178 + return -EPROBE_DEFER;
1181 + ret = pisnd_spi_gpio_init(dev);
1184 + printe("SPI GPIO init failed: %d\n", ret);
1185 + spi_dev_put(pisnd_spi_device);
1186 + pisnd_spi_device = NULL;
1187 + pisnd_spi_gpio_uninit();
1191 + ret = spi_read_info();
1194 + printe("Reading card info failed: %d\n", ret);
1195 + spi_dev_put(pisnd_spi_device);
1196 + pisnd_spi_device = NULL;
1197 + pisnd_spi_gpio_uninit();
1201 + /* Flash the LEDs. */
1202 + spi_transfer16(0xf008);
1204 + ret = pisnd_spi_gpio_irq_init(dev);
1206 + printe("SPI irq request failed: %d\n", ret);
1207 + spi_dev_put(pisnd_spi_device);
1208 + pisnd_spi_device = NULL;
1209 + pisnd_spi_gpio_irq_uninit();
1210 + pisnd_spi_gpio_uninit();
1213 + ret = pisnd_init_workqueues();
1215 + printe("Workqueue initialization failed: %d\n", ret);
1216 + spi_dev_put(pisnd_spi_device);
1217 + pisnd_spi_device = NULL;
1218 + pisnd_spi_gpio_irq_uninit();
1219 + pisnd_spi_gpio_uninit();
1220 + pisnd_uninit_workqueues();
1224 + if (pisnd_spi_has_more()) {
1225 + printd("data is available, scheduling from init\n");
1226 + pisnd_schedule_process(TASK_PROCESS);
1232 +static void pisnd_spi_uninit(void)
1234 + pisnd_uninit_workqueues();
1236 + spi_dev_put(pisnd_spi_device);
1237 + pisnd_spi_device = NULL;
1239 + pisnd_spi_gpio_irq_uninit();
1240 + pisnd_spi_gpio_uninit();
1243 +static void pisnd_spi_flash_leds(uint8_t duration)
1245 + g_ledFlashDuration = duration;
1246 + g_ledFlashDurationChanged = true;
1247 + printd("schedule from spi_flash_leds\n");
1248 + pisnd_schedule_process(TASK_PROCESS);
1251 +static void pisnd_spi_flush(void)
1253 + while (!kfifo_is_empty(&spi_fifo_out)) {
1254 + pisnd_spi_start();
1255 + flush_workqueue(pisnd_workqueue);
1259 +static void pisnd_spi_start(void)
1261 + printd("schedule from spi_start\n");
1262 + pisnd_schedule_process(TASK_PROCESS);
1265 +static uint8_t pisnd_spi_recv(uint8_t *buffer, uint8_t length)
1267 + return kfifo_out(&spi_fifo_in, buffer, length);
1270 +static void pisnd_spi_set_callback(pisnd_spi_recv_cb cb, void *data)
1272 + g_recvData = data;
1273 + g_recvCallback = cb;
1276 +static const char *pisnd_spi_get_serial(void)
1278 + if (strlen(g_serial_num))
1279 + return g_serial_num;
1284 +static const char *pisnd_spi_get_id(void)
1292 +static const char *pisnd_spi_get_version(void)
1294 + if (strlen(g_version))
1300 +static const struct of_device_id pisound_of_match[] = {
1301 + { .compatible = "blokaslabs,pisound", },
1302 + { .compatible = "blokaslabs,pisound-spi", },
1311 +static int pisnd_ctl_info(struct snd_kcontrol *kcontrol,
1312 + struct snd_ctl_elem_info *uinfo)
1314 + if (kcontrol->private_value == SWITCH) {
1315 + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
1317 + uinfo->value.integer.min = 0;
1318 + uinfo->value.integer.max = 1;
1320 + } else if (kcontrol->private_value == VOLUME) {
1321 + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1323 + uinfo->value.integer.min = 0;
1324 + uinfo->value.integer.max = 100;
1330 +static int pisnd_ctl_get(struct snd_kcontrol *kcontrol,
1331 + struct snd_ctl_elem_value *ucontrol)
1333 + if (kcontrol->private_value == SWITCH) {
1334 + ucontrol->value.integer.value[0] = 1;
1336 + } else if (kcontrol->private_value == VOLUME) {
1337 + ucontrol->value.integer.value[0] = 100;
1344 +static struct snd_kcontrol_new pisnd_ctl[] = {
1346 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1347 + .name = "PCM Playback Switch",
1349 + .private_value = SWITCH,
1350 + .access = SNDRV_CTL_ELEM_ACCESS_READ,
1351 + .info = pisnd_ctl_info,
1352 + .get = pisnd_ctl_get,
1355 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1356 + .name = "PCM Playback Volume",
1358 + .private_value = VOLUME,
1359 + .access = SNDRV_CTL_ELEM_ACCESS_READ,
1360 + .info = pisnd_ctl_info,
1361 + .get = pisnd_ctl_get,
1365 +static int pisnd_ctl_init(struct snd_card *card)
1369 + for (i = 0; i < ARRAY_SIZE(pisnd_ctl); ++i) {
1370 + err = snd_ctl_add(card, snd_ctl_new1(&pisnd_ctl[i], NULL));
1378 +static int pisnd_ctl_uninit(void)
1383 +static struct gpio_desc *osr0, *osr1, *osr2;
1384 +static struct gpio_desc *reset;
1385 +static struct gpio_desc *button;
1387 +static int pisnd_hw_params(
1388 + struct snd_pcm_substream *substream,
1389 + struct snd_pcm_hw_params *params
1392 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
1393 + struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
1395 + /* Pisound runs on fixed 32 clock counts per channel,
1396 + * as generated by the master ADC.
1398 + snd_soc_dai_set_bclk_ratio(cpu_dai, 32*2);
1400 + printd("rate = %d\n", params_rate(params));
1401 + printd("ch = %d\n", params_channels(params));
1402 + printd("bits = %u\n",
1403 + snd_pcm_format_physical_width(params_format(params)));
1404 + printd("format = %d\n", params_format(params));
1406 + gpiod_set_value(reset, false);
1408 + switch (params_rate(params)) {
1410 + gpiod_set_value(osr0, true);
1411 + gpiod_set_value(osr1, false);
1412 + gpiod_set_value(osr2, false);
1415 + gpiod_set_value(osr0, true);
1416 + gpiod_set_value(osr1, false);
1417 + gpiod_set_value(osr2, true);
1420 + gpiod_set_value(osr0, true);
1421 + gpiod_set_value(osr1, true);
1422 + gpiod_set_value(osr2, true);
1425 + printe("Unsupported rate %u!\n", params_rate(params));
1429 + gpiod_set_value(reset, true);
1434 +static unsigned int rates[3] = {
1435 + 48000, 96000, 192000
1438 +static struct snd_pcm_hw_constraint_list constraints_rates = {
1439 + .count = ARRAY_SIZE(rates),
1444 +static int pisnd_startup(struct snd_pcm_substream *substream)
1446 + int err = snd_pcm_hw_constraint_list(
1447 + substream->runtime,
1449 + SNDRV_PCM_HW_PARAM_RATE,
1450 + &constraints_rates
1456 + err = snd_pcm_hw_constraint_single(
1457 + substream->runtime,
1458 + SNDRV_PCM_HW_PARAM_CHANNELS,
1465 + err = snd_pcm_hw_constraint_mask64(
1466 + substream->runtime,
1467 + SNDRV_PCM_HW_PARAM_FORMAT,
1468 + SNDRV_PCM_FMTBIT_S16_LE |
1469 + SNDRV_PCM_FMTBIT_S24_LE |
1470 + SNDRV_PCM_FMTBIT_S32_LE
1479 +static struct snd_soc_ops pisnd_ops = {
1480 + .startup = pisnd_startup,
1481 + .hw_params = pisnd_hw_params,
1484 +SND_SOC_DAILINK_DEFS(pisnd,
1485 + DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")),
1486 + DAILINK_COMP_ARRAY(COMP_DUMMY()),
1487 + DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0")));
1489 +static struct snd_soc_dai_link pisnd_dai[] = {
1491 + .name = "pisound",
1492 + .stream_name = "pisound",
1494 + SND_SOC_DAIFMT_I2S |
1495 + SND_SOC_DAIFMT_NB_NF |
1496 + SND_SOC_DAIFMT_CBM_CFM,
1497 + .ops = &pisnd_ops,
1498 + SND_SOC_DAILINK_REG(pisnd),
1502 +static int pisnd_card_probe(struct snd_soc_card *card)
1504 + int err = pisnd_midi_init(card->snd_card);
1507 + printe("pisnd_midi_init failed: %d\n", err);
1511 + err = pisnd_ctl_init(card->snd_card);
1513 + printe("pisnd_ctl_init failed: %d\n", err);
1520 +static int pisnd_card_remove(struct snd_soc_card *card)
1522 + pisnd_ctl_uninit();
1523 + pisnd_midi_uninit();
1527 +static struct snd_soc_card pisnd_card = {
1528 + .name = "pisound",
1529 + .owner = THIS_MODULE,
1530 + .dai_link = pisnd_dai,
1531 + .num_links = ARRAY_SIZE(pisnd_dai),
1532 + .probe = pisnd_card_probe,
1533 + .remove = pisnd_card_remove,
1536 +static int pisnd_init_gpio(struct device *dev)
1538 + osr0 = gpiod_get_index(dev, "osr", 0, GPIOD_ASIS);
1539 + osr1 = gpiod_get_index(dev, "osr", 1, GPIOD_ASIS);
1540 + osr2 = gpiod_get_index(dev, "osr", 2, GPIOD_ASIS);
1542 + reset = gpiod_get_index(dev, "reset", 0, GPIOD_ASIS);
1544 + button = gpiod_get_index(dev, "button", 0, GPIOD_ASIS);
1546 + gpiod_direction_output(osr0, 1);
1547 + gpiod_direction_output(osr1, 1);
1548 + gpiod_direction_output(osr2, 1);
1549 + gpiod_direction_output(reset, 1);
1551 + gpiod_set_value(reset, false);
1552 + gpiod_set_value(osr0, true);
1553 + gpiod_set_value(osr1, false);
1554 + gpiod_set_value(osr2, false);
1555 + gpiod_set_value(reset, true);
1557 + gpiod_export(button, false);
1562 +static int pisnd_uninit_gpio(void)
1566 + struct gpio_desc **gpios[] = {
1567 + &osr0, &osr1, &osr2, &reset, &button,
1570 + gpiod_unexport(button);
1572 + for (i = 0; i < ARRAY_SIZE(gpios); ++i) {
1573 + if (*gpios[i] == NULL) {
1574 + printd("weird, GPIO[%d] is NULL already\n", i);
1578 + gpiod_put(*gpios[i]);
1585 +static struct kobject *pisnd_kobj;
1587 +static ssize_t pisnd_serial_show(
1588 + struct kobject *kobj,
1589 + struct kobj_attribute *attr,
1593 + return sprintf(buf, "%s\n", pisnd_spi_get_serial());
1596 +static ssize_t pisnd_id_show(
1597 + struct kobject *kobj,
1598 + struct kobj_attribute *attr,
1602 + return sprintf(buf, "%s\n", pisnd_spi_get_id());
1605 +static ssize_t pisnd_version_show(
1606 + struct kobject *kobj,
1607 + struct kobj_attribute *attr,
1611 + return sprintf(buf, "%s\n", pisnd_spi_get_version());
1614 +static ssize_t pisnd_led_store(
1615 + struct kobject *kobj,
1616 + struct kobj_attribute *attr,
1624 + err = kstrtou32(buf, 10, &timeout);
1626 + if (err == 0 && timeout <= 255)
1627 + pisnd_spi_flash_leds(timeout);
1632 +static struct kobj_attribute pisnd_serial_attribute =
1633 + __ATTR(serial, 0444, pisnd_serial_show, NULL);
1634 +static struct kobj_attribute pisnd_id_attribute =
1635 + __ATTR(id, 0444, pisnd_id_show, NULL);
1636 +static struct kobj_attribute pisnd_version_attribute =
1637 + __ATTR(version, 0444, pisnd_version_show, NULL);
1638 +static struct kobj_attribute pisnd_led_attribute =
1639 + __ATTR(led, 0644, NULL, pisnd_led_store);
1641 +static struct attribute *attrs[] = {
1642 + &pisnd_serial_attribute.attr,
1643 + &pisnd_id_attribute.attr,
1644 + &pisnd_version_attribute.attr,
1645 + &pisnd_led_attribute.attr,
1649 +static struct attribute_group attr_group = { .attrs = attrs };
1651 +static int pisnd_probe(struct platform_device *pdev)
1656 + ret = pisnd_spi_init(&pdev->dev);
1658 + printe("pisnd_spi_init failed: %d\n", ret);
1662 + printi("Detected Pisound card:\n");
1663 + printi("\tSerial: %s\n", pisnd_spi_get_serial());
1664 + printi("\tVersion: %s\n", pisnd_spi_get_version());
1665 + printi("\tId: %s\n", pisnd_spi_get_id());
1667 + pisnd_kobj = kobject_create_and_add("pisound", kernel_kobj);
1668 + if (!pisnd_kobj) {
1669 + pisnd_spi_uninit();
1673 + ret = sysfs_create_group(pisnd_kobj, &attr_group);
1675 + pisnd_spi_uninit();
1676 + kobject_put(pisnd_kobj);
1680 + pisnd_init_gpio(&pdev->dev);
1681 + pisnd_card.dev = &pdev->dev;
1683 + if (pdev->dev.of_node) {
1684 + struct device_node *i2s_node;
1686 + i2s_node = of_parse_phandle(
1687 + pdev->dev.of_node,
1692 + for (i = 0; i < pisnd_card.num_links; ++i) {
1693 + struct snd_soc_dai_link *dai = &pisnd_dai[i];
1696 + dai->cpus->dai_name = NULL;
1697 + dai->cpus->of_node = i2s_node;
1698 + dai->platforms->name = NULL;
1699 + dai->platforms->of_node = i2s_node;
1700 + dai->stream_name = pisnd_spi_get_serial();
1705 + ret = snd_soc_register_card(&pisnd_card);
1708 + if (ret != -EPROBE_DEFER)
1709 + printe("snd_soc_register_card() failed: %d\n", ret);
1710 + pisnd_uninit_gpio();
1711 + kobject_put(pisnd_kobj);
1712 + pisnd_spi_uninit();
1718 +static int pisnd_remove(struct platform_device *pdev)
1720 + printi("Unloading.\n");
1723 + kobject_put(pisnd_kobj);
1724 + pisnd_kobj = NULL;
1727 + pisnd_spi_uninit();
1730 + gpiod_set_value(reset, false);
1731 + pisnd_uninit_gpio();
1733 + return snd_soc_unregister_card(&pisnd_card);
1736 +MODULE_DEVICE_TABLE(of, pisound_of_match);
1738 +static struct platform_driver pisnd_driver = {
1740 + .name = "snd-rpi-pisound",
1741 + .owner = THIS_MODULE,
1742 + .of_match_table = pisound_of_match,
1744 + .probe = pisnd_probe,
1745 + .remove = pisnd_remove,
1748 +module_platform_driver(pisnd_driver);
1750 +MODULE_AUTHOR("Giedrius Trainavicius <giedrius@blokas.io>");
1751 +MODULE_DESCRIPTION("ASoC Driver for Pisound, https://blokas.io/pisound");
1752 +MODULE_LICENSE("GPL v2");