firmware-utils: bump to git HEAD
[openwrt/openwrt.git] / target / linux / bcm27xx / patches-5.4 / 950-0071-Support-for-Blokas-Labs-pisound-board.patch
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
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 Fix for Pisound kernel module in Real Time kernel configuration.
49
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
53 instead.
54
55 Pisound: Remove spinlock usage around spi_sync
56
57 ASoC: pisound: use modern dai_link style
58
59 Signed-off-by: Hui Wang <hui.wang@canonical.com>
60
61 ASoC: pisound: fix the parameter for spi_device_match
62
63 Signed-off-by: Hui Wang <hui.wang@canonical.com>
64 ---
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
71
72 --- /dev/null
73 +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
74 @@ -0,0 +1,463 @@
75 +Device tree binding vendor prefix registry. Keep list in alphabetical order.
76 +
77 +This isn't an exhaustive list, but you should add new prefixes to it before
78 +using them to avoid name-space collisions.
79 +
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.
88 +adh AD Holdings Plc.
89 +adi Analog Devices, Inc.
90 +advantech Advantech Corporation
91 +aeroflexgaisler Aeroflex Gaisler AB
92 +al Annapurna Labs
93 +allo Allo.com
94 +allwinner Allwinner Technology Co., Ltd.
95 +alphascale AlphaScale Integrated Circuits Systems, Inc.
96 +altr Altera Corp.
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.
104 +ams AMS AG
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.
112 +arctic Arctic Sand
113 +aries Aries Embedded GmbH
114 +arm ARM Ltd.
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.
128 +avnet Avnet, Inc.
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
141 +calxeda Calxeda
142 +capella Capella Microsystems, Inc
143 +cascoda Cascoda, Ltd.
144 +catalyst Catalyst Semiconductor, Inc.
145 +cavium Cavium, Inc.
146 +cdns Cadence Design Systems Inc.
147 +cdtech CDTech(H.K.) Electronics Limited
148 +ceva Ceva, Inc.
149 +chipidea Chipidea, Inc
150 +chipone ChipOne
151 +chipspark ChipSPARK
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
182 +dmo Data Modul AG
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
189 +ebv EBV Elektronik
190 +eckelmann Eckelmann AG
191 +edt Emerging Display Technologies
192 +eeti eGalax_eMPIA Technology Inc
193 +elan Elan Microelectronic Corp.
194 +elgin Elgin S/A.
195 +embest Shenzhen Embest Technology Co., Ltd.
196 +emlid Emlid, 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.
202 +epcos EPCOS AG
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
211 +excito Excito
212 +ezchip EZchip Semiconductor
213 +facebook Facebook
214 +fairphone Fairphone B.V.
215 +faraday Faraday Technology Corporation
216 +fastrax Fastrax Oy
217 +fcs Fairchild Semiconductor
218 +feiyang Shenzhen Fly Young Technology Co.,LTD.
219 +firefly Firefly
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.
237 +google Google, Inc.
238 +grinn Grinn
239 +grmn Garmin Limited
240 +gumstix Gumstix, Inc.
241 +gw Gateworks Corporation
242 +hannstar HannStar Display Corporation
243 +haoyu Haoyu Microelectronic Co. Ltd.
244 +hardkernel Hardkernel Co., Ltd
245 +hideep HiDeep Inc.
246 +himax Himax Technologies, Inc.
247 +hisilicon Hisilicon Limited.
248 +hit Hitachi Ltd.
249 +hitex Hitex Development Tools
250 +holt Holt Integrated Circuits, Inc.
251 +honeywell Honeywell
252 +hp Hewlett Packard
253 +holtek Holtek Semiconductor, Inc.
254 +hwacom HwaCom Systems Inc.
255 +i2se I2SE GmbH
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
272 +isee ISEE 2007 S.L.
273 +isil Intersil
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
283 +khadas Khadas
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
291 +lacie LaCie
292 +laird Laird PLC
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.
298 +lg LG Corporation
299 +libretech Shenzhen Libre Technology Co., Ltd
300 +licheepi Lichee Pi
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
312 +mbvl Mobiveil Inc.
313 +mcube mCube
314 +meas Measurement Specialties
315 +mediatek MediaTek Inc.
316 +megachips MegaChips
317 +mele Shenzhen MeLE Digital Technology Ltd.
318 +melexis Melexis N.V.
319 +melfas MELFAS Inc.
320 +mellanox Mellanox Technologies
321 +memsic MEMSIC Inc.
322 +merrii Merrii Technology Co., Ltd.
323 +micrel Micrel Inc.
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.
333 +moxa Moxa Inc.
334 +mpl MPL AG
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.
347 +netgear NETGEAR
348 +netlogic Broadcom Corporation (formerly NetLogic Microsystems)
349 +netron-dy Netron DY
350 +netxeon Shenzhen Netxeon Technology CO., LTD
351 +nexbox Nexbox
352 +nextthing Next Thing Co.
353 +newhaven Newhaven Display International
354 +ni National Instruments
355 +nintendo Nintendo
356 +nlt NLT Technologies, Ltd.
357 +nokia Nokia
358 +nordic Nordic Semiconductor
359 +novtech NovTech, Inc.
360 +nutsboard NutsBoard
361 +nuvoton Nuvoton Technology Corporation
362 +nvd New Vision Display
363 +nvidia NVIDIA
364 +nxp NXP Semiconductors
365 +okaya Okaya Electric America, Inc.
366 +oki Oki Electric Industry Co., Ltd.
367 +olimex OLIMEX 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
375 +option Option NV
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
390 +pine64 Pine64
391 +pixcir PIXCIR MICROELECTRONICS Co., Ltd
392 +plantower Plantower Co., Ltd
393 +plathome Plat'Home Co., Ltd.
394 +plda PLDA
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
405 +qi Qi Hardware
406 +qiaodian QiaoDian XianShi Corporation
407 +qnap QNAP Systems, Inc.
408 +radxa Radxa
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
429 +schindler Schindler
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
435 +sgx SGX Sensortech
436 +sharp Sharp Corporation
437 +shimafuji Shimafuji Electric, Inc.
438 +si-en Si-En Technology Ltd.
439 +sifive SiFive, Inc.
440 +sigma Sigma Designs, Inc.
441 +sii Seiko Instruments, Inc.
442 +sil Silicon Image
443 +silabs Silicon Laboratories
444 +silead Silead Inc.
445 +silergy Silergy Corp.
446 +siliconmitus Silicon Mitus, Inc.
447 +simtek
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
453 +snps Synopsys, Inc.
454 +socionext Socionext Inc.
455 +solidrun SolidRun
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
463 +startek Startek
464 +ste ST-Ericsson
465 +stericsson ST-Ericsson
466 +summit Summit microelectronics
467 +sunchip Shenzhen Sunchip Technology Co., Ltd
468 +SUNW Sun Microsystems, Inc
469 +swir Sierra Wireless
470 +syna Synaptics Inc.
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.
486 +topeet Topeet
487 +toradex Toradex AG
488 +toshiba Toshiba Corporation
489 +toumaz Toumaz
490 +tpk TPK U.S.A. LLC
491 +tplink TP-LINK Technologies Co., Ltd.
492 +tpo TPO
493 +tronfy Tronfy
494 +tronsmart Tronsmart
495 +truly Truly Semiconductors Limited
496 +tsd Theobroma Systems Design und Consulting GmbH
497 +tyan Tyan Computer Corporation
498 +u-blox u-blox
499 +ucrobotics uCRobotics
500 +ubnt Ubiquiti Networks
501 +udoo Udoo
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.
506 +v3 V3 Semiconductor
507 +vamrs Vamrs 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.
519 +wexler Wexler
520 +whwave Shenzhen whwave Electronics, Inc.
521 +wi2wi Wi2Wi, Inc.
522 +winbond Winbond Electronics corp.
523 +winstar Winstar Display Corp.
524 +wlf Wolfson Microelectronics
525 +wm Wondermedia Technologies, Inc.
526 +x-powers X-Powers
527 +xes Extreme Engineering Solutions (X-ES)
528 +xillybus Xillybus Ltd.
529 +xlnx Xilinx
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
536 +zte ZTE Corp.
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
542 "^bitmain,.*":
543 description: Bitmain Technologies
544 + "^blokaslabs,.*":
545 + description: Vilniaus Blokas UAB
546 "^boe,.*":
547 description: BOE Technology Group Co., Ltd.
548 "^bosch,.*":
549 --- /dev/null
550 +++ b/sound/soc/bcm/pisound.c
551 @@ -0,0 +1,1201 @@
552 +/*
553 + * Pisound Linux kernel module.
554 + * Copyright (C) 2016-2019 Vilniaus Blokas UAB, https://blokas.io/pisound
555 + *
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
559 + * License.
560 + *
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.
565 + *
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.
570 + */
571 +
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>
583 +
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>
592 +
593 +static int pisnd_spi_init(struct device *dev);
594 +static void pisnd_spi_uninit(void);
595 +
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);
599 +
600 +typedef void (*pisnd_spi_recv_cb)(void *data);
601 +static void pisnd_spi_set_callback(pisnd_spi_recv_cb cb, void *data);
602 +
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);
606 +
607 +static int pisnd_midi_init(struct snd_card *card);
608 +static void pisnd_midi_uninit(void);
609 +
610 +enum task_e {
611 + TASK_PROCESS = 0,
612 +};
613 +
614 +static void pisnd_schedule_process(enum task_e task);
615 +
616 +#define PISOUND_LOG_PREFIX "pisound: "
617 +
618 +#ifdef PISOUND_DEBUG
619 +# define printd(...) pr_alert(PISOUND_LOG_PREFIX __VA_ARGS__)
620 +#else
621 +# define printd(...) do {} while (0)
622 +#endif
623 +
624 +#define printe(...) pr_err(PISOUND_LOG_PREFIX __VA_ARGS__)
625 +#define printi(...) pr_info(PISOUND_LOG_PREFIX __VA_ARGS__)
626 +
627 +static struct snd_rawmidi *g_rmidi;
628 +static struct snd_rawmidi_substream *g_midi_output_substream;
629 +
630 +static int pisnd_output_open(struct snd_rawmidi_substream *substream)
631 +{
632 + g_midi_output_substream = substream;
633 + return 0;
634 +}
635 +
636 +static int pisnd_output_close(struct snd_rawmidi_substream *substream)
637 +{
638 + g_midi_output_substream = NULL;
639 + return 0;
640 +}
641 +
642 +static void pisnd_output_trigger(
643 + struct snd_rawmidi_substream *substream,
644 + int up
645 + )
646 +{
647 + if (substream != g_midi_output_substream) {
648 + printe("MIDI output trigger called for an unexpected stream!");
649 + return;
650 + }
651 +
652 + if (!up)
653 + return;
654 +
655 + pisnd_spi_start();
656 +}
657 +
658 +static void pisnd_output_drain(struct snd_rawmidi_substream *substream)
659 +{
660 + pisnd_spi_flush();
661 +}
662 +
663 +static int pisnd_input_open(struct snd_rawmidi_substream *substream)
664 +{
665 + return 0;
666 +}
667 +
668 +static int pisnd_input_close(struct snd_rawmidi_substream *substream)
669 +{
670 + return 0;
671 +}
672 +
673 +static void pisnd_midi_recv_callback(void *substream)
674 +{
675 + uint8_t data[128];
676 + uint8_t n = 0;
677 +
678 + while ((n = pisnd_spi_recv(data, sizeof(data)))) {
679 + int res = snd_rawmidi_receive(substream, data, n);
680 + (void)res;
681 + printd("midi recv %u bytes, res = %d\n", n, res);
682 + }
683 +}
684 +
685 +static void pisnd_input_trigger(struct snd_rawmidi_substream *substream, int up)
686 +{
687 + if (up) {
688 + pisnd_spi_set_callback(pisnd_midi_recv_callback, substream);
689 + pisnd_schedule_process(TASK_PROCESS);
690 + } else {
691 + pisnd_spi_set_callback(NULL, NULL);
692 + }
693 +}
694 +
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,
700 +};
701 +
702 +static struct snd_rawmidi_ops pisnd_input_ops = {
703 + .open = pisnd_input_open,
704 + .close = pisnd_input_close,
705 + .trigger = pisnd_input_trigger,
706 +};
707 +
708 +static void pisnd_get_port_info(
709 + struct snd_rawmidi *rmidi,
710 + int number,
711 + struct snd_seq_port_info *seq_port_info
712 + )
713 +{
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;
719 +}
720 +
721 +static struct snd_rawmidi_global_ops pisnd_global_ops = {
722 + .get_port_info = pisnd_get_port_info,
723 +};
724 +
725 +static int pisnd_midi_init(struct snd_card *card)
726 +{
727 + int err;
728 +
729 + g_midi_output_substream = NULL;
730 +
731 + err = snd_rawmidi_new(card, "pisound MIDI", 0, 1, 1, &g_rmidi);
732 +
733 + if (err < 0) {
734 + printe("snd_rawmidi_new failed: %d\n", err);
735 + return err;
736 + }
737 +
738 + strcpy(g_rmidi->name, "pisound MIDI ");
739 + strcat(g_rmidi->name, pisnd_spi_get_serial());
740 +
741 + g_rmidi->info_flags =
742 + SNDRV_RAWMIDI_INFO_OUTPUT |
743 + SNDRV_RAWMIDI_INFO_INPUT |
744 + SNDRV_RAWMIDI_INFO_DUPLEX;
745 +
746 + g_rmidi->ops = &pisnd_global_ops;
747 +
748 + g_rmidi->private_data = (void *)0;
749 +
750 + snd_rawmidi_set_ops(
751 + g_rmidi,
752 + SNDRV_RAWMIDI_STREAM_OUTPUT,
753 + &pisnd_output_ops
754 + );
755 +
756 + snd_rawmidi_set_ops(
757 + g_rmidi,
758 + SNDRV_RAWMIDI_STREAM_INPUT,
759 + &pisnd_input_ops
760 + );
761 +
762 + return 0;
763 +}
764 +
765 +static void pisnd_midi_uninit(void)
766 +{
767 +}
768 +
769 +static void *g_recvData;
770 +static pisnd_spi_recv_cb g_recvCallback;
771 +
772 +#define FIFO_SIZE 4096
773 +
774 +static char g_serial_num[11];
775 +static char g_id[25];
776 +static char g_version[5];
777 +
778 +static uint8_t g_ledFlashDuration;
779 +static bool g_ledFlashDurationChanged;
780 +
781 +DEFINE_KFIFO(spi_fifo_in, uint8_t, FIFO_SIZE);
782 +DEFINE_KFIFO(spi_fifo_out, uint8_t, FIFO_SIZE);
783 +
784 +static struct gpio_desc *data_available;
785 +static struct gpio_desc *spi_reset;
786 +
787 +static struct spi_device *pisnd_spi_device;
788 +
789 +static struct workqueue_struct *pisnd_workqueue;
790 +static struct work_struct pisnd_work_process;
791 +
792 +static void pisnd_work_handler(struct work_struct *work);
793 +
794 +static void spi_transfer(const uint8_t *txbuf, uint8_t *rxbuf, int len);
795 +static uint16_t spi_transfer16(uint16_t val);
796 +
797 +static int pisnd_init_workqueues(void)
798 +{
799 + pisnd_workqueue = create_singlethread_workqueue("pisnd_workqueue");
800 + INIT_WORK(&pisnd_work_process, pisnd_work_handler);
801 +
802 + return 0;
803 +}
804 +
805 +static void pisnd_uninit_workqueues(void)
806 +{
807 + flush_workqueue(pisnd_workqueue);
808 + destroy_workqueue(pisnd_workqueue);
809 +
810 + pisnd_workqueue = NULL;
811 +}
812 +
813 +static bool pisnd_spi_has_more(void)
814 +{
815 + return gpiod_get_value(data_available);
816 +}
817 +
818 +static void pisnd_schedule_process(enum task_e task)
819 +{
820 + if (pisnd_spi_device != NULL &&
821 + pisnd_workqueue != NULL &&
822 + !work_pending(&pisnd_work_process)
823 + ) {
824 + printd("schedule: has more = %d\n", pisnd_spi_has_more());
825 + if (task == TASK_PROCESS)
826 + queue_work(pisnd_workqueue, &pisnd_work_process);
827 + }
828 +}
829 +
830 +static irqreturn_t data_available_interrupt_handler(int irq, void *dev_id)
831 +{
832 + if (irq == gpiod_to_irq(data_available) && pisnd_spi_has_more()) {
833 + printd("schedule from irq\n");
834 + pisnd_schedule_process(TASK_PROCESS);
835 + }
836 +
837 + return IRQ_HANDLED;
838 +}
839 +
840 +static uint16_t spi_transfer16(uint16_t val)
841 +{
842 + uint8_t txbuf[2];
843 + uint8_t rxbuf[2];
844 +
845 + if (!pisnd_spi_device) {
846 + printe("pisnd_spi_device null, returning\n");
847 + return 0;
848 + }
849 +
850 + txbuf[0] = val >> 8;
851 + txbuf[1] = val & 0xff;
852 +
853 + spi_transfer(txbuf, rxbuf, sizeof(txbuf));
854 +
855 + printd("received: %02x%02x\n", rxbuf[0], rxbuf[1]);
856 +
857 + return (rxbuf[0] << 8) | rxbuf[1];
858 +}
859 +
860 +static void spi_transfer(const uint8_t *txbuf, uint8_t *rxbuf, int len)
861 +{
862 + int err;
863 + struct spi_transfer transfer;
864 + struct spi_message msg;
865 +
866 + memset(rxbuf, 0, len);
867 +
868 + if (!pisnd_spi_device) {
869 + printe("pisnd_spi_device null, returning\n");
870 + return;
871 + }
872 +
873 + spi_message_init(&msg);
874 +
875 + memset(&transfer, 0, sizeof(transfer));
876 +
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);
883 +
884 + err = spi_sync(pisnd_spi_device, &msg);
885 +
886 + if (err < 0) {
887 + printe("spi_sync error %d\n", err);
888 + return;
889 + }
890 +
891 + printd("hasMore %d\n", pisnd_spi_has_more());
892 +}
893 +
894 +static int spi_read_bytes(char *dst, size_t length, uint8_t *bytesRead)
895 +{
896 + uint16_t rx;
897 + uint8_t size;
898 + uint8_t i;
899 +
900 + memset(dst, 0, length);
901 + *bytesRead = 0;
902 +
903 + rx = spi_transfer16(0);
904 + if (!(rx >> 8))
905 + return -EINVAL;
906 +
907 + size = rx & 0xff;
908 +
909 + if (size > length)
910 + return -EINVAL;
911 +
912 + for (i = 0; i < size; ++i) {
913 + rx = spi_transfer16(0);
914 + if (!(rx >> 8))
915 + return -EINVAL;
916 +
917 + dst[i] = rx & 0xff;
918 + }
919 +
920 + *bytesRead = i;
921 +
922 + return 0;
923 +}
924 +
925 +static int spi_device_match(struct device *dev, const void *data)
926 +{
927 + struct spi_device *spi = container_of(dev, struct spi_device, dev);
928 +
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);
932 +
933 + if (strcmp("pisound-spi", spi->modalias) == 0) {
934 + printi("\tFound!\n");
935 + return 1;
936 + }
937 +
938 + printe("\tNot found!\n");
939 + return 0;
940 +}
941 +
942 +static struct spi_device *pisnd_spi_find_device(void)
943 +{
944 + struct device *dev;
945 +
946 + printi("Searching for spi device...\n");
947 + dev = bus_find_device(&spi_bus_type, NULL, NULL, spi_device_match);
948 + if (dev != NULL)
949 + return container_of(dev, struct spi_device, dev);
950 + else
951 + return NULL;
952 +}
953 +
954 +static void pisnd_work_handler(struct work_struct *work)
955 +{
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;
960 + unsigned long now;
961 + uint8_t val;
962 + uint8_t txbuf[TRANSFER_SIZE];
963 + uint8_t rxbuf[TRANSFER_SIZE];
964 + uint8_t midibuf[TRANSFER_SIZE];
965 + int i, n;
966 + bool had_data;
967 +
968 + unsigned long last_transfer_at = jiffies;
969 +
970 + if (work == &pisnd_work_process) {
971 + if (pisnd_spi_device == NULL)
972 + return;
973 +
974 + do {
975 + if (g_midi_output_substream &&
976 + kfifo_avail(&spi_fifo_out) >= sizeof(midibuf)) {
977 +
978 + n = snd_rawmidi_transmit_peek(
979 + g_midi_output_substream,
980 + midibuf, sizeof(midibuf)
981 + );
982 +
983 + if (n > 0) {
984 + for (i = 0; i < n; ++i)
985 + kfifo_put(
986 + &spi_fifo_out,
987 + midibuf[i]
988 + );
989 + snd_rawmidi_transmit_ack(
990 + g_midi_output_substream,
991 + i
992 + );
993 + }
994 + }
995 +
996 + had_data = false;
997 + memset(txbuf, 0, sizeof(txbuf));
998 + for (i = 0; i < sizeof(txbuf) &&
999 + out_buffer_used < PISOUND_OUTPUT_BUFFER_SIZE;
1000 + i += 2) {
1001 +
1002 + val = 0;
1003 +
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;
1011 + txbuf[i+1] = val;
1012 + ++out_buffer_used;
1013 + }
1014 + }
1015 +
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
1020 + * rate.
1021 + */
1022 + now = jiffies;
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;
1029 +
1030 + for (i = 0; i < sizeof(rxbuf); i += 2) {
1031 + if (rxbuf[i]) {
1032 + kfifo_put(&spi_fifo_in, rxbuf[i+1]);
1033 + if (kfifo_len(&spi_fifo_in) > 16 &&
1034 + g_recvCallback)
1035 + g_recvCallback(g_recvData);
1036 + had_data = true;
1037 + }
1038 + }
1039 + } while (had_data
1040 + || !kfifo_is_empty(&spi_fifo_out)
1041 + || pisnd_spi_has_more()
1042 + || g_ledFlashDurationChanged
1043 + );
1044 +
1045 + if (!kfifo_is_empty(&spi_fifo_in) && g_recvCallback)
1046 + g_recvCallback(g_recvData);
1047 + }
1048 +}
1049 +
1050 +static int pisnd_spi_gpio_init(struct device *dev)
1051 +{
1052 + spi_reset = gpiod_get_index(dev, "reset", 1, GPIOD_ASIS);
1053 + data_available = gpiod_get_index(dev, "data_available", 0, GPIOD_ASIS);
1054 +
1055 + gpiod_direction_output(spi_reset, 1);
1056 + gpiod_direction_input(data_available);
1057 +
1058 + /* Reset the slave. */
1059 + gpiod_set_value(spi_reset, false);
1060 + mdelay(1);
1061 + gpiod_set_value(spi_reset, true);
1062 +
1063 + /* Give time for spi slave to start. */
1064 + mdelay(64);
1065 +
1066 + return 0;
1067 +}
1068 +
1069 +static void pisnd_spi_gpio_uninit(void)
1070 +{
1071 + gpiod_set_value(spi_reset, false);
1072 + gpiod_put(spi_reset);
1073 + spi_reset = NULL;
1074 +
1075 + gpiod_put(data_available);
1076 + data_available = NULL;
1077 +}
1078 +
1079 +static int pisnd_spi_gpio_irq_init(struct device *dev)
1080 +{
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",
1086 + NULL
1087 + );
1088 +}
1089 +
1090 +static void pisnd_spi_gpio_irq_uninit(void)
1091 +{
1092 + free_irq(gpiod_to_irq(data_available), NULL);
1093 +}
1094 +
1095 +static int spi_read_info(void)
1096 +{
1097 + uint16_t tmp;
1098 + uint8_t count;
1099 + uint8_t n;
1100 + uint8_t i;
1101 + uint8_t j;
1102 + char buffer[257];
1103 + int ret;
1104 + char *p;
1105 +
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));
1109 +
1110 + tmp = spi_transfer16(0);
1111 +
1112 + if (!(tmp >> 8))
1113 + return -EINVAL;
1114 +
1115 + count = tmp & 0xff;
1116 +
1117 + for (i = 0; i < count; ++i) {
1118 + memset(buffer, 0, sizeof(buffer));
1119 + ret = spi_read_bytes(buffer, sizeof(buffer)-1, &n);
1120 +
1121 + if (ret < 0)
1122 + return ret;
1123 +
1124 + switch (i) {
1125 + case 0:
1126 + if (n != 2)
1127 + return -EINVAL;
1128 +
1129 + snprintf(
1130 + g_version,
1131 + sizeof(g_version),
1132 + "%x.%02x",
1133 + buffer[0],
1134 + buffer[1]
1135 + );
1136 + break;
1137 + case 1:
1138 + if (n >= sizeof(g_serial_num))
1139 + return -EINVAL;
1140 +
1141 + memcpy(g_serial_num, buffer, sizeof(g_serial_num));
1142 + break;
1143 + case 2:
1144 + {
1145 + if (n >= sizeof(g_id))
1146 + return -EINVAL;
1147 +
1148 + p = g_id;
1149 + for (j = 0; j < n; ++j)
1150 + p += sprintf(p, "%02x", buffer[j]);
1151 + }
1152 + break;
1153 + default:
1154 + break;
1155 + }
1156 + }
1157 +
1158 + return 0;
1159 +}
1160 +
1161 +static int pisnd_spi_init(struct device *dev)
1162 +{
1163 + int ret;
1164 + struct spi_device *spi;
1165 +
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));
1169 +
1170 + spi = pisnd_spi_find_device();
1171 +
1172 + if (spi != NULL) {
1173 + printd("initializing spi!\n");
1174 + pisnd_spi_device = spi;
1175 + ret = spi_setup(pisnd_spi_device);
1176 + } else {
1177 + printe("SPI device not found, deferring!\n");
1178 + return -EPROBE_DEFER;
1179 + }
1180 +
1181 + ret = pisnd_spi_gpio_init(dev);
1182 +
1183 + if (ret < 0) {
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();
1188 + return ret;
1189 + }
1190 +
1191 + ret = spi_read_info();
1192 +
1193 + if (ret < 0) {
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();
1198 + return ret;
1199 + }
1200 +
1201 + /* Flash the LEDs. */
1202 + spi_transfer16(0xf008);
1203 +
1204 + ret = pisnd_spi_gpio_irq_init(dev);
1205 + if (ret < 0) {
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();
1211 + }
1212 +
1213 + ret = pisnd_init_workqueues();
1214 + if (ret != 0) {
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();
1221 + return ret;
1222 + }
1223 +
1224 + if (pisnd_spi_has_more()) {
1225 + printd("data is available, scheduling from init\n");
1226 + pisnd_schedule_process(TASK_PROCESS);
1227 + }
1228 +
1229 + return 0;
1230 +}
1231 +
1232 +static void pisnd_spi_uninit(void)
1233 +{
1234 + pisnd_uninit_workqueues();
1235 +
1236 + spi_dev_put(pisnd_spi_device);
1237 + pisnd_spi_device = NULL;
1238 +
1239 + pisnd_spi_gpio_irq_uninit();
1240 + pisnd_spi_gpio_uninit();
1241 +}
1242 +
1243 +static void pisnd_spi_flash_leds(uint8_t duration)
1244 +{
1245 + g_ledFlashDuration = duration;
1246 + g_ledFlashDurationChanged = true;
1247 + printd("schedule from spi_flash_leds\n");
1248 + pisnd_schedule_process(TASK_PROCESS);
1249 +}
1250 +
1251 +static void pisnd_spi_flush(void)
1252 +{
1253 + while (!kfifo_is_empty(&spi_fifo_out)) {
1254 + pisnd_spi_start();
1255 + flush_workqueue(pisnd_workqueue);
1256 + }
1257 +}
1258 +
1259 +static void pisnd_spi_start(void)
1260 +{
1261 + printd("schedule from spi_start\n");
1262 + pisnd_schedule_process(TASK_PROCESS);
1263 +}
1264 +
1265 +static uint8_t pisnd_spi_recv(uint8_t *buffer, uint8_t length)
1266 +{
1267 + return kfifo_out(&spi_fifo_in, buffer, length);
1268 +}
1269 +
1270 +static void pisnd_spi_set_callback(pisnd_spi_recv_cb cb, void *data)
1271 +{
1272 + g_recvData = data;
1273 + g_recvCallback = cb;
1274 +}
1275 +
1276 +static const char *pisnd_spi_get_serial(void)
1277 +{
1278 + if (strlen(g_serial_num))
1279 + return g_serial_num;
1280 +
1281 + return "";
1282 +}
1283 +
1284 +static const char *pisnd_spi_get_id(void)
1285 +{
1286 + if (strlen(g_id))
1287 + return g_id;
1288 +
1289 + return "";
1290 +}
1291 +
1292 +static const char *pisnd_spi_get_version(void)
1293 +{
1294 + if (strlen(g_version))
1295 + return g_version;
1296 +
1297 + return "";
1298 +}
1299 +
1300 +static const struct of_device_id pisound_of_match[] = {
1301 + { .compatible = "blokaslabs,pisound", },
1302 + { .compatible = "blokaslabs,pisound-spi", },
1303 + {},
1304 +};
1305 +
1306 +enum {
1307 + SWITCH = 0,
1308 + VOLUME = 1,
1309 +};
1310 +
1311 +static int pisnd_ctl_info(struct snd_kcontrol *kcontrol,
1312 + struct snd_ctl_elem_info *uinfo)
1313 +{
1314 + if (kcontrol->private_value == SWITCH) {
1315 + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
1316 + uinfo->count = 1;
1317 + uinfo->value.integer.min = 0;
1318 + uinfo->value.integer.max = 1;
1319 + return 0;
1320 + } else if (kcontrol->private_value == VOLUME) {
1321 + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1322 + uinfo->count = 1;
1323 + uinfo->value.integer.min = 0;
1324 + uinfo->value.integer.max = 100;
1325 + return 0;
1326 + }
1327 + return -EINVAL;
1328 +}
1329 +
1330 +static int pisnd_ctl_get(struct snd_kcontrol *kcontrol,
1331 + struct snd_ctl_elem_value *ucontrol)
1332 +{
1333 + if (kcontrol->private_value == SWITCH) {
1334 + ucontrol->value.integer.value[0] = 1;
1335 + return 0;
1336 + } else if (kcontrol->private_value == VOLUME) {
1337 + ucontrol->value.integer.value[0] = 100;
1338 + return 0;
1339 + }
1340 +
1341 + return -EINVAL;
1342 +}
1343 +
1344 +static struct snd_kcontrol_new pisnd_ctl[] = {
1345 + {
1346 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1347 + .name = "PCM Playback Switch",
1348 + .index = 0,
1349 + .private_value = SWITCH,
1350 + .access = SNDRV_CTL_ELEM_ACCESS_READ,
1351 + .info = pisnd_ctl_info,
1352 + .get = pisnd_ctl_get,
1353 + },
1354 + {
1355 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1356 + .name = "PCM Playback Volume",
1357 + .index = 0,
1358 + .private_value = VOLUME,
1359 + .access = SNDRV_CTL_ELEM_ACCESS_READ,
1360 + .info = pisnd_ctl_info,
1361 + .get = pisnd_ctl_get,
1362 + },
1363 +};
1364 +
1365 +static int pisnd_ctl_init(struct snd_card *card)
1366 +{
1367 + int err, i;
1368 +
1369 + for (i = 0; i < ARRAY_SIZE(pisnd_ctl); ++i) {
1370 + err = snd_ctl_add(card, snd_ctl_new1(&pisnd_ctl[i], NULL));
1371 + if (err < 0)
1372 + return err;
1373 + }
1374 +
1375 + return 0;
1376 +}
1377 +
1378 +static int pisnd_ctl_uninit(void)
1379 +{
1380 + return 0;
1381 +}
1382 +
1383 +static struct gpio_desc *osr0, *osr1, *osr2;
1384 +static struct gpio_desc *reset;
1385 +static struct gpio_desc *button;
1386 +
1387 +static int pisnd_hw_params(
1388 + struct snd_pcm_substream *substream,
1389 + struct snd_pcm_hw_params *params
1390 + )
1391 +{
1392 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
1393 + struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
1394 +
1395 + /* Pisound runs on fixed 32 clock counts per channel,
1396 + * as generated by the master ADC.
1397 + */
1398 + snd_soc_dai_set_bclk_ratio(cpu_dai, 32*2);
1399 +
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));
1405 +
1406 + gpiod_set_value(reset, false);
1407 +
1408 + switch (params_rate(params)) {
1409 + case 48000:
1410 + gpiod_set_value(osr0, true);
1411 + gpiod_set_value(osr1, false);
1412 + gpiod_set_value(osr2, false);
1413 + break;
1414 + case 96000:
1415 + gpiod_set_value(osr0, true);
1416 + gpiod_set_value(osr1, false);
1417 + gpiod_set_value(osr2, true);
1418 + break;
1419 + case 192000:
1420 + gpiod_set_value(osr0, true);
1421 + gpiod_set_value(osr1, true);
1422 + gpiod_set_value(osr2, true);
1423 + break;
1424 + default:
1425 + printe("Unsupported rate %u!\n", params_rate(params));
1426 + return -EINVAL;
1427 + }
1428 +
1429 + gpiod_set_value(reset, true);
1430 +
1431 + return 0;
1432 +}
1433 +
1434 +static unsigned int rates[3] = {
1435 + 48000, 96000, 192000
1436 +};
1437 +
1438 +static struct snd_pcm_hw_constraint_list constraints_rates = {
1439 + .count = ARRAY_SIZE(rates),
1440 + .list = rates,
1441 + .mask = 0,
1442 +};
1443 +
1444 +static int pisnd_startup(struct snd_pcm_substream *substream)
1445 +{
1446 + int err = snd_pcm_hw_constraint_list(
1447 + substream->runtime,
1448 + 0,
1449 + SNDRV_PCM_HW_PARAM_RATE,
1450 + &constraints_rates
1451 + );
1452 +
1453 + if (err < 0)
1454 + return err;
1455 +
1456 + err = snd_pcm_hw_constraint_single(
1457 + substream->runtime,
1458 + SNDRV_PCM_HW_PARAM_CHANNELS,
1459 + 2
1460 + );
1461 +
1462 + if (err < 0)
1463 + return err;
1464 +
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
1471 + );
1472 +
1473 + if (err < 0)
1474 + return err;
1475 +
1476 + return 0;
1477 +}
1478 +
1479 +static struct snd_soc_ops pisnd_ops = {
1480 + .startup = pisnd_startup,
1481 + .hw_params = pisnd_hw_params,
1482 +};
1483 +
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")));
1488 +
1489 +static struct snd_soc_dai_link pisnd_dai[] = {
1490 + {
1491 + .name = "pisound",
1492 + .stream_name = "pisound",
1493 + .dai_fmt =
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),
1499 + },
1500 +};
1501 +
1502 +static int pisnd_card_probe(struct snd_soc_card *card)
1503 +{
1504 + int err = pisnd_midi_init(card->snd_card);
1505 +
1506 + if (err < 0) {
1507 + printe("pisnd_midi_init failed: %d\n", err);
1508 + return err;
1509 + }
1510 +
1511 + err = pisnd_ctl_init(card->snd_card);
1512 + if (err < 0) {
1513 + printe("pisnd_ctl_init failed: %d\n", err);
1514 + return err;
1515 + }
1516 +
1517 + return 0;
1518 +}
1519 +
1520 +static int pisnd_card_remove(struct snd_soc_card *card)
1521 +{
1522 + pisnd_ctl_uninit();
1523 + pisnd_midi_uninit();
1524 + return 0;
1525 +}
1526 +
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,
1534 +};
1535 +
1536 +static int pisnd_init_gpio(struct device *dev)
1537 +{
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);
1541 +
1542 + reset = gpiod_get_index(dev, "reset", 0, GPIOD_ASIS);
1543 +
1544 + button = gpiod_get_index(dev, "button", 0, GPIOD_ASIS);
1545 +
1546 + gpiod_direction_output(osr0, 1);
1547 + gpiod_direction_output(osr1, 1);
1548 + gpiod_direction_output(osr2, 1);
1549 + gpiod_direction_output(reset, 1);
1550 +
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);
1556 +
1557 + gpiod_export(button, false);
1558 +
1559 + return 0;
1560 +}
1561 +
1562 +static int pisnd_uninit_gpio(void)
1563 +{
1564 + int i;
1565 +
1566 + struct gpio_desc **gpios[] = {
1567 + &osr0, &osr1, &osr2, &reset, &button,
1568 + };
1569 +
1570 + gpiod_unexport(button);
1571 +
1572 + for (i = 0; i < ARRAY_SIZE(gpios); ++i) {
1573 + if (*gpios[i] == NULL) {
1574 + printd("weird, GPIO[%d] is NULL already\n", i);
1575 + continue;
1576 + }
1577 +
1578 + gpiod_put(*gpios[i]);
1579 + *gpios[i] = NULL;
1580 + }
1581 +
1582 + return 0;
1583 +}
1584 +
1585 +static struct kobject *pisnd_kobj;
1586 +
1587 +static ssize_t pisnd_serial_show(
1588 + struct kobject *kobj,
1589 + struct kobj_attribute *attr,
1590 + char *buf
1591 + )
1592 +{
1593 + return sprintf(buf, "%s\n", pisnd_spi_get_serial());
1594 +}
1595 +
1596 +static ssize_t pisnd_id_show(
1597 + struct kobject *kobj,
1598 + struct kobj_attribute *attr,
1599 + char *buf
1600 + )
1601 +{
1602 + return sprintf(buf, "%s\n", pisnd_spi_get_id());
1603 +}
1604 +
1605 +static ssize_t pisnd_version_show(
1606 + struct kobject *kobj,
1607 + struct kobj_attribute *attr,
1608 + char *buf
1609 + )
1610 +{
1611 + return sprintf(buf, "%s\n", pisnd_spi_get_version());
1612 +}
1613 +
1614 +static ssize_t pisnd_led_store(
1615 + struct kobject *kobj,
1616 + struct kobj_attribute *attr,
1617 + const char *buf,
1618 + size_t length
1619 + )
1620 +{
1621 + uint32_t timeout;
1622 + int err;
1623 +
1624 + err = kstrtou32(buf, 10, &timeout);
1625 +
1626 + if (err == 0 && timeout <= 255)
1627 + pisnd_spi_flash_leds(timeout);
1628 +
1629 + return length;
1630 +}
1631 +
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);
1640 +
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,
1646 + NULL
1647 +};
1648 +
1649 +static struct attribute_group attr_group = { .attrs = attrs };
1650 +
1651 +static int pisnd_probe(struct platform_device *pdev)
1652 +{
1653 + int ret = 0;
1654 + int i;
1655 +
1656 + ret = pisnd_spi_init(&pdev->dev);
1657 + if (ret < 0) {
1658 + printe("pisnd_spi_init failed: %d\n", ret);
1659 + return ret;
1660 + }
1661 +
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());
1666 +
1667 + pisnd_kobj = kobject_create_and_add("pisound", kernel_kobj);
1668 + if (!pisnd_kobj) {
1669 + pisnd_spi_uninit();
1670 + return -ENOMEM;
1671 + }
1672 +
1673 + ret = sysfs_create_group(pisnd_kobj, &attr_group);
1674 + if (ret < 0) {
1675 + pisnd_spi_uninit();
1676 + kobject_put(pisnd_kobj);
1677 + return -ENOMEM;
1678 + }
1679 +
1680 + pisnd_init_gpio(&pdev->dev);
1681 + pisnd_card.dev = &pdev->dev;
1682 +
1683 + if (pdev->dev.of_node) {
1684 + struct device_node *i2s_node;
1685 +
1686 + i2s_node = of_parse_phandle(
1687 + pdev->dev.of_node,
1688 + "i2s-controller",
1689 + 0
1690 + );
1691 +
1692 + for (i = 0; i < pisnd_card.num_links; ++i) {
1693 + struct snd_soc_dai_link *dai = &pisnd_dai[i];
1694 +
1695 + if (i2s_node) {
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();
1701 + }
1702 + }
1703 + }
1704 +
1705 + ret = snd_soc_register_card(&pisnd_card);
1706 +
1707 + if (ret < 0) {
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();
1713 + }
1714 +
1715 + return ret;
1716 +}
1717 +
1718 +static int pisnd_remove(struct platform_device *pdev)
1719 +{
1720 + printi("Unloading.\n");
1721 +
1722 + if (pisnd_kobj) {
1723 + kobject_put(pisnd_kobj);
1724 + pisnd_kobj = NULL;
1725 + }
1726 +
1727 + pisnd_spi_uninit();
1728 +
1729 + /* Turn off */
1730 + gpiod_set_value(reset, false);
1731 + pisnd_uninit_gpio();
1732 +
1733 + return snd_soc_unregister_card(&pisnd_card);
1734 +}
1735 +
1736 +MODULE_DEVICE_TABLE(of, pisound_of_match);
1737 +
1738 +static struct platform_driver pisnd_driver = {
1739 + .driver = {
1740 + .name = "snd-rpi-pisound",
1741 + .owner = THIS_MODULE,
1742 + .of_match_table = pisound_of_match,
1743 + },
1744 + .probe = pisnd_probe,
1745 + .remove = pisnd_remove,
1746 +};
1747 +
1748 +module_platform_driver(pisnd_driver);
1749 +
1750 +MODULE_AUTHOR("Giedrius Trainavicius <giedrius@blokas.io>");
1751 +MODULE_DESCRIPTION("ASoC Driver for Pisound, https://blokas.io/pisound");
1752 +MODULE_LICENSE("GPL v2");