brcm2708: add kernel 4.14 support
[openwrt/staging/lynxis.git] / target / linux / brcm2708 / patches-4.14 / 950-0138-Updates-for-Pisound-module-code.patch
1 From 5f3557a2e88b324e026d44f8fb7eb3ea37bba16b Mon Sep 17 00:00:00 2001
2 From: Giedrius Trainavicius <giedrius@blokas.io>
3 Date: Tue, 25 Oct 2016 01:47:20 +0300
4 Subject: [PATCH 138/454] Updates for Pisound module code:
5
6 * Merged 'Fix a warning in DEBUG builds' (1c8b82b).
7 * Updating some strings and copyright information.
8 * Fix for handling high load of MIDI input and output.
9 * Use dual rate oversampling ratio for 96kHz instead of single
10 rate one.
11
12 Signed-off-by: Giedrius Trainavicius <giedrius@blokas.io>
13 ---
14 .../arm/boot/dts/overlays/pisound-overlay.dts | 4 +-
15 sound/soc/bcm/pisound.c | 209 ++++++++++++------
16 2 files changed, 146 insertions(+), 67 deletions(-)
17
18 --- a/arch/arm/boot/dts/overlays/pisound-overlay.dts
19 +++ b/arch/arm/boot/dts/overlays/pisound-overlay.dts
20 @@ -1,6 +1,6 @@
21 /*
22 - * pisound Linux kernel module.
23 - * Copyright (C) 2016 Vilniaus Blokas UAB, http://blokas.io/pisound
24 + * Pisound Linux kernel module.
25 + * Copyright (C) 2016-2017 Vilniaus Blokas UAB, https://blokas.io/pisound
26 *
27 * This program is free software; you can redistribute it and/or
28 * modify it under the terms of the GNU General Public License
29 --- a/sound/soc/bcm/pisound.c
30 +++ b/sound/soc/bcm/pisound.c
31 @@ -1,6 +1,6 @@
32 /*
33 - * pisound Linux kernel module.
34 - * Copyright (C) 2016 Vilniaus Blokas UAB, http://blokas.io/pisound
35 + * Pisound Linux kernel module.
36 + * Copyright (C) 2016-2017 Vilniaus Blokas UAB, https://blokas.io/pisound
37 *
38 * This program is free software; you can redistribute it and/or
39 * modify it under the terms of the GNU General Public License
40 @@ -28,6 +28,7 @@
41 #include <linux/spi/spi.h>
42 #include <linux/interrupt.h>
43 #include <linux/kfifo.h>
44 +#include <linux/jiffies.h>
45
46 #include <sound/core.h>
47 #include <sound/pcm.h>
48 @@ -41,7 +42,8 @@
49 static int pisnd_spi_init(struct device *dev);
50 static void pisnd_spi_uninit(void);
51
52 -static void pisnd_spi_send(uint8_t val);
53 +static void pisnd_spi_flush(void);
54 +static void pisnd_spi_start(void);
55 static uint8_t pisnd_spi_recv(uint8_t *buffer, uint8_t length);
56
57 typedef void (*pisnd_spi_recv_cb)(void *data);
58 @@ -56,7 +58,7 @@ static void pisnd_midi_uninit(void);
59
60 #define PISOUND_LOG_PREFIX "pisound: "
61
62 -#ifdef DEBUG
63 +#ifdef PISOUND_DEBUG
64 # define printd(...) pr_alert(PISOUND_LOG_PREFIX __VA_ARGS__)
65 #else
66 # define printd(...) do {} while (0)
67 @@ -65,13 +67,18 @@ static void pisnd_midi_uninit(void);
68 #define printe(...) pr_err(PISOUND_LOG_PREFIX __VA_ARGS__)
69 #define printi(...) pr_info(PISOUND_LOG_PREFIX __VA_ARGS__)
70
71 +static struct snd_rawmidi *g_rmidi;
72 +static struct snd_rawmidi_substream *g_midi_output_substream;
73 +
74 static int pisnd_output_open(struct snd_rawmidi_substream *substream)
75 {
76 + g_midi_output_substream = substream;
77 return 0;
78 }
79
80 static int pisnd_output_close(struct snd_rawmidi_substream *substream)
81 {
82 + g_midi_output_substream = NULL;
83 return 0;
84 }
85
86 @@ -80,26 +87,20 @@ static void pisnd_output_trigger(
87 int up
88 )
89 {
90 - uint8_t data;
91 + if (substream != g_midi_output_substream) {
92 + printe("MIDI output trigger called for an unexpected stream!");
93 + return;
94 + }
95
96 if (!up)
97 return;
98
99 - while (snd_rawmidi_transmit_peek(substream, &data, 1)) {
100 - pisnd_spi_send(data);
101 - snd_rawmidi_transmit_ack(substream, 1);
102 - }
103 + pisnd_spi_start();
104 }
105
106 static void pisnd_output_drain(struct snd_rawmidi_substream *substream)
107 {
108 - uint8_t data;
109 -
110 - while (snd_rawmidi_transmit_peek(substream, &data, 1)) {
111 - pisnd_spi_send(data);
112 -
113 - snd_rawmidi_transmit_ack(substream, 1);
114 - }
115 + pisnd_spi_flush();
116 }
117
118 static int pisnd_input_open(struct snd_rawmidi_substream *substream)
119 @@ -120,7 +121,7 @@ static void pisnd_midi_recv_callback(voi
120 while ((n = pisnd_spi_recv(data, sizeof(data)))) {
121 int res = snd_rawmidi_receive(substream, data, n);
122 (void)res;
123 - printd("midi recv 0x%02x, res = %d\n", data, res);
124 + printd("midi recv %u bytes, res = %d\n", n, res);
125 }
126 }
127
128 @@ -134,8 +135,6 @@ static void pisnd_input_trigger(struct s
129 }
130 }
131
132 -static struct snd_rawmidi *g_rmidi;
133 -
134 static struct snd_rawmidi_ops pisnd_output_ops = {
135 .open = pisnd_output_open,
136 .close = pisnd_output_close,
137 @@ -168,7 +167,11 @@ static struct snd_rawmidi_global_ops pis
138
139 static int pisnd_midi_init(struct snd_card *card)
140 {
141 - int err = snd_rawmidi_new(card, "pisound MIDI", 0, 1, 1, &g_rmidi);
142 + int err;
143 +
144 + g_midi_output_substream = NULL;
145 +
146 + err = snd_rawmidi_new(card, "pisound MIDI", 0, 1, 1, &g_rmidi);
147
148 if (err < 0) {
149 printe("snd_rawmidi_new failed: %d\n", err);
150 @@ -209,7 +212,7 @@ static void pisnd_midi_uninit(void)
151 static void *g_recvData;
152 static pisnd_spi_recv_cb g_recvCallback;
153
154 -#define FIFO_SIZE 512
155 +#define FIFO_SIZE 4096
156
157 static char g_serial_num[11];
158 static char g_id[25];
159 @@ -231,6 +234,7 @@ static struct work_struct pisnd_work_pro
160
161 static void pisnd_work_handler(struct work_struct *work);
162
163 +static void spi_transfer(const uint8_t *txbuf, uint8_t *rxbuf, int len);
164 static uint16_t spi_transfer16(uint16_t val);
165
166 static int pisnd_init_workqueues(void)
167 @@ -285,9 +289,6 @@ static unsigned long spilockflags;
168
169 static uint16_t spi_transfer16(uint16_t val)
170 {
171 - int err;
172 - struct spi_transfer transfer;
173 - struct spi_message msg;
174 uint8_t txbuf[2];
175 uint8_t rxbuf[2];
176
177 @@ -296,19 +297,38 @@ static uint16_t spi_transfer16(uint16_t
178 return 0;
179 }
180
181 + txbuf[0] = val >> 8;
182 + txbuf[1] = val & 0xff;
183 +
184 + spi_transfer(txbuf, rxbuf, sizeof(txbuf));
185 +
186 + printd("received: %02x%02x\n", rxbuf[0], rxbuf[1]);
187 +
188 + return (rxbuf[0] << 8) | rxbuf[1];
189 +}
190 +
191 +static void spi_transfer(const uint8_t *txbuf, uint8_t *rxbuf, int len)
192 +{
193 + int err;
194 + struct spi_transfer transfer;
195 + struct spi_message msg;
196 +
197 + memset(rxbuf, 0, sizeof(txbuf));
198 +
199 + if (!pisnd_spi_device) {
200 + printe("pisnd_spi_device null, returning\n");
201 + return;
202 + }
203 +
204 spi_message_init(&msg);
205
206 memset(&transfer, 0, sizeof(transfer));
207 - memset(&rxbuf, 0, sizeof(rxbuf));
208
209 - txbuf[0] = val >> 8;
210 - txbuf[1] = val & 0xff;
211 -
212 - transfer.tx_buf = &txbuf;
213 - transfer.rx_buf = &rxbuf;
214 - transfer.len = sizeof(txbuf);
215 - transfer.speed_hz = 125000;
216 - transfer.delay_usecs = 100;
217 + transfer.tx_buf = txbuf;
218 + transfer.rx_buf = rxbuf;
219 + transfer.len = len;
220 + transfer.speed_hz = 100000;
221 + transfer.delay_usecs = 10;
222 spi_message_add_tail(&transfer, &msg);
223
224 spin_lock_irqsave(&spilock, spilockflags);
225 @@ -317,13 +337,10 @@ static uint16_t spi_transfer16(uint16_t
226
227 if (err < 0) {
228 printe("spi_sync error %d\n", err);
229 - return 0;
230 + return;
231 }
232
233 - printd("received: %02x%02x\n", rxbuf[0], rxbuf[1]);
234 printd("hasMore %d\n", pisnd_spi_has_more());
235 -
236 - return (rxbuf[0] << 8) | rxbuf[1];
237 }
238
239 static int spi_read_bytes(char *dst, size_t length, uint8_t *bytesRead)
240 @@ -335,7 +352,7 @@ static int spi_read_bytes(char *dst, siz
241 memset(dst, 0, length);
242 *bytesRead = 0;
243
244 - rx = spi_transfer16(0);
245 + rx = spi_transfer16(0);
246 if (!(rx >> 8))
247 return -EINVAL;
248
249 @@ -388,35 +405,90 @@ static struct spi_device *pisnd_spi_find
250
251 static void pisnd_work_handler(struct work_struct *work)
252 {
253 - uint16_t rx;
254 - uint16_t tx;
255 + enum { TRANSFER_SIZE = 4 };
256 + enum { PISOUND_OUTPUT_BUFFER_SIZE = 128 };
257 + enum { MIDI_BYTES_PER_SECOND = 3125 };
258 + int out_buffer_used = 0;
259 + unsigned long now;
260 uint8_t val;
261 + uint8_t txbuf[TRANSFER_SIZE];
262 + uint8_t rxbuf[TRANSFER_SIZE];
263 + uint8_t midibuf[TRANSFER_SIZE];
264 + int i, n;
265 + bool had_data;
266 +
267 + unsigned long last_transfer_at = jiffies;
268
269 if (work == &pisnd_work_process) {
270 if (pisnd_spi_device == NULL)
271 return;
272
273 do {
274 - val = 0;
275 - tx = 0;
276 + if (g_midi_output_substream &&
277 + kfifo_avail(&spi_fifo_out) >= sizeof(midibuf)) {
278
279 - if (g_ledFlashDurationChanged) {
280 - tx = 0xf000 | g_ledFlashDuration;
281 - g_ledFlashDuration = 0;
282 - g_ledFlashDurationChanged = false;
283 - } else if (kfifo_get(&spi_fifo_out, &val)) {
284 - tx = 0x0f00 | val;
285 + n = snd_rawmidi_transmit_peek(
286 + g_midi_output_substream,
287 + midibuf, sizeof(midibuf)
288 + );
289 +
290 + if (n > 0) {
291 + for (i = 0; i < n; ++i)
292 + kfifo_put(
293 + &spi_fifo_out,
294 + midibuf[i]
295 + );
296 + snd_rawmidi_transmit_ack(
297 + g_midi_output_substream,
298 + i
299 + );
300 + }
301 }
302
303 - rx = spi_transfer16(tx);
304 + had_data = false;
305 + memset(txbuf, 0, sizeof(txbuf));
306 + for (i = 0; i < sizeof(txbuf) &&
307 + out_buffer_used < PISOUND_OUTPUT_BUFFER_SIZE;
308 + i += 2) {
309 +
310 + val = 0;
311 +
312 + if (g_ledFlashDurationChanged) {
313 + txbuf[i+0] = 0xf0;
314 + txbuf[i+1] = g_ledFlashDuration;
315 + g_ledFlashDuration = 0;
316 + g_ledFlashDurationChanged = false;
317 + } else if (kfifo_get(&spi_fifo_out, &val)) {
318 + txbuf[i+0] = 0x0f;
319 + txbuf[i+1] = val;
320 + ++out_buffer_used;
321 + }
322 + }
323
324 - if (rx & 0xff00) {
325 - kfifo_put(&spi_fifo_in, rx & 0xff);
326 - if (kfifo_len(&spi_fifo_in) > 16
327 - && g_recvCallback)
328 - g_recvCallback(g_recvData);
329 + spi_transfer(txbuf, rxbuf, sizeof(txbuf));
330 + /* Estimate the Pisound's MIDI output buffer usage, so
331 + * that we don't overflow it. Space in the buffer should
332 + * be becoming available at the UART MIDI byte transfer
333 + * rate.
334 + */
335 + now = jiffies;
336 + out_buffer_used -=
337 + (MIDI_BYTES_PER_SECOND / HZ) /
338 + (now - last_transfer_at);
339 + if (out_buffer_used < 0)
340 + out_buffer_used = 0;
341 + last_transfer_at = now;
342 +
343 + for (i = 0; i < sizeof(rxbuf); i += 2) {
344 + if (rxbuf[i]) {
345 + kfifo_put(&spi_fifo_in, rxbuf[i+1]);
346 + if (kfifo_len(&spi_fifo_in) > 16 &&
347 + g_recvCallback)
348 + g_recvCallback(g_recvData);
349 + had_data = true;
350 + }
351 }
352 - } while (rx != 0
353 + } while (had_data
354 || !kfifo_is_empty(&spi_fifo_out)
355 || pisnd_spi_has_more()
356 || g_ledFlashDurationChanged
357 @@ -492,7 +564,7 @@ static int spi_read_info(void)
358 if (!(tmp >> 8))
359 return -EINVAL;
360
361 - count = tmp & 0xff;
362 + count = tmp & 0xff;
363
364 for (i = 0; i < count; ++i) {
365 memset(buffer, 0, sizeof(buffer));
366 @@ -628,10 +700,17 @@ static void pisnd_spi_flash_leds(uint8_t
367 pisnd_schedule_process(TASK_PROCESS);
368 }
369
370 -static void pisnd_spi_send(uint8_t val)
371 +static void pisnd_spi_flush(void)
372 +{
373 + while (!kfifo_is_empty(&spi_fifo_out)) {
374 + pisnd_spi_start();
375 + flush_workqueue(pisnd_workqueue);
376 + }
377 +}
378 +
379 +static void pisnd_spi_start(void)
380 {
381 - kfifo_put(&spi_fifo_out, val);
382 - printd("schedule from spi_send\n");
383 + printd("schedule from spi_start\n");
384 pisnd_schedule_process(TASK_PROCESS);
385 }
386
387 @@ -765,7 +844,7 @@ static int pisnd_hw_params(
388 struct snd_soc_pcm_runtime *rtd = substream->private_data;
389 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
390
391 - /* pisound runs on fixed 32 clock counts per channel,
392 + /* Pisound runs on fixed 32 clock counts per channel,
393 * as generated by the master ADC.
394 */
395 snd_soc_dai_set_bclk_ratio(cpu_dai, 32*2);
396 @@ -786,8 +865,8 @@ static int pisnd_hw_params(
397 break;
398 case 96000:
399 gpiod_set_value(osr0, true);
400 - gpiod_set_value(osr1, true);
401 - gpiod_set_value(osr2, false);
402 + gpiod_set_value(osr1, false);
403 + gpiod_set_value(osr2, true);
404 break;
405 case 192000:
406 gpiod_set_value(osr0, true);
407 @@ -1030,7 +1109,7 @@ static int pisnd_probe(struct platform_d
408 return ret;
409 }
410
411 - printi("Detected pisound card:\n");
412 + printi("Detected Pisound card:\n");
413 printi("\tSerial: %s\n", pisnd_spi_get_serial());
414 printi("\tVersion: %s\n", pisnd_spi_get_version());
415 printi("\tId: %s\n", pisnd_spi_get_id());
416 @@ -1119,5 +1198,5 @@ static struct platform_driver pisnd_driv
417 module_platform_driver(pisnd_driver);
418
419 MODULE_AUTHOR("Giedrius Trainavicius <giedrius@blokas.io>");
420 -MODULE_DESCRIPTION("ASoC Driver for pisound, http://blokas.io/pisound");
421 +MODULE_DESCRIPTION("ASoC Driver for Pisound, https://blokas.io/pisound");
422 MODULE_LICENSE("GPL v2");