aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/brcm2708/patches-4.14/950-0138-Updates-for-Pisound-module-code.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/brcm2708/patches-4.14/950-0138-Updates-for-Pisound-module-code.patch')
-rw-r--r--target/linux/brcm2708/patches-4.14/950-0138-Updates-for-Pisound-module-code.patch422
1 files changed, 422 insertions, 0 deletions
diff --git a/target/linux/brcm2708/patches-4.14/950-0138-Updates-for-Pisound-module-code.patch b/target/linux/brcm2708/patches-4.14/950-0138-Updates-for-Pisound-module-code.patch
new file mode 100644
index 0000000000..af501d56f4
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.14/950-0138-Updates-for-Pisound-module-code.patch
@@ -0,0 +1,422 @@
+From 5f3557a2e88b324e026d44f8fb7eb3ea37bba16b Mon Sep 17 00:00:00 2001
+From: Giedrius Trainavicius <giedrius@blokas.io>
+Date: Tue, 25 Oct 2016 01:47:20 +0300
+Subject: [PATCH 138/454] Updates for Pisound module code:
+
+ * Merged 'Fix a warning in DEBUG builds' (1c8b82b).
+ * Updating some strings and copyright information.
+ * Fix for handling high load of MIDI input and output.
+ * Use dual rate oversampling ratio for 96kHz instead of single
+ rate one.
+
+Signed-off-by: Giedrius Trainavicius <giedrius@blokas.io>
+---
+ .../arm/boot/dts/overlays/pisound-overlay.dts | 4 +-
+ sound/soc/bcm/pisound.c | 209 ++++++++++++------
+ 2 files changed, 146 insertions(+), 67 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/pisound-overlay.dts
++++ b/arch/arm/boot/dts/overlays/pisound-overlay.dts
+@@ -1,6 +1,6 @@
+ /*
+- * pisound Linux kernel module.
+- * Copyright (C) 2016 Vilniaus Blokas UAB, http://blokas.io/pisound
++ * Pisound Linux kernel module.
++ * Copyright (C) 2016-2017 Vilniaus Blokas UAB, https://blokas.io/pisound
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+--- a/sound/soc/bcm/pisound.c
++++ b/sound/soc/bcm/pisound.c
+@@ -1,6 +1,6 @@
+ /*
+- * pisound Linux kernel module.
+- * Copyright (C) 2016 Vilniaus Blokas UAB, http://blokas.io/pisound
++ * Pisound Linux kernel module.
++ * Copyright (C) 2016-2017 Vilniaus Blokas UAB, https://blokas.io/pisound
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+@@ -28,6 +28,7 @@
+ #include <linux/spi/spi.h>
+ #include <linux/interrupt.h>
+ #include <linux/kfifo.h>
++#include <linux/jiffies.h>
+
+ #include <sound/core.h>
+ #include <sound/pcm.h>
+@@ -41,7 +42,8 @@
+ static int pisnd_spi_init(struct device *dev);
+ static void pisnd_spi_uninit(void);
+
+-static void pisnd_spi_send(uint8_t val);
++static void pisnd_spi_flush(void);
++static void pisnd_spi_start(void);
+ static uint8_t pisnd_spi_recv(uint8_t *buffer, uint8_t length);
+
+ typedef void (*pisnd_spi_recv_cb)(void *data);
+@@ -56,7 +58,7 @@ static void pisnd_midi_uninit(void);
+
+ #define PISOUND_LOG_PREFIX "pisound: "
+
+-#ifdef DEBUG
++#ifdef PISOUND_DEBUG
+ # define printd(...) pr_alert(PISOUND_LOG_PREFIX __VA_ARGS__)
+ #else
+ # define printd(...) do {} while (0)
+@@ -65,13 +67,18 @@ static void pisnd_midi_uninit(void);
+ #define printe(...) pr_err(PISOUND_LOG_PREFIX __VA_ARGS__)
+ #define printi(...) pr_info(PISOUND_LOG_PREFIX __VA_ARGS__)
+
++static struct snd_rawmidi *g_rmidi;
++static struct snd_rawmidi_substream *g_midi_output_substream;
++
+ static int pisnd_output_open(struct snd_rawmidi_substream *substream)
+ {
++ g_midi_output_substream = substream;
+ return 0;
+ }
+
+ static int pisnd_output_close(struct snd_rawmidi_substream *substream)
+ {
++ g_midi_output_substream = NULL;
+ return 0;
+ }
+
+@@ -80,26 +87,20 @@ static void pisnd_output_trigger(
+ int up
+ )
+ {
+- uint8_t data;
++ if (substream != g_midi_output_substream) {
++ printe("MIDI output trigger called for an unexpected stream!");
++ return;
++ }
+
+ if (!up)
+ return;
+
+- while (snd_rawmidi_transmit_peek(substream, &data, 1)) {
+- pisnd_spi_send(data);
+- snd_rawmidi_transmit_ack(substream, 1);
+- }
++ pisnd_spi_start();
+ }
+
+ static void pisnd_output_drain(struct snd_rawmidi_substream *substream)
+ {
+- uint8_t data;
+-
+- while (snd_rawmidi_transmit_peek(substream, &data, 1)) {
+- pisnd_spi_send(data);
+-
+- snd_rawmidi_transmit_ack(substream, 1);
+- }
++ pisnd_spi_flush();
+ }
+
+ static int pisnd_input_open(struct snd_rawmidi_substream *substream)
+@@ -120,7 +121,7 @@ static void pisnd_midi_recv_callback(voi
+ while ((n = pisnd_spi_recv(data, sizeof(data)))) {
+ int res = snd_rawmidi_receive(substream, data, n);
+ (void)res;
+- printd("midi recv 0x%02x, res = %d\n", data, res);
++ printd("midi recv %u bytes, res = %d\n", n, res);
+ }
+ }
+
+@@ -134,8 +135,6 @@ static void pisnd_input_trigger(struct s
+ }
+ }
+
+-static struct snd_rawmidi *g_rmidi;
+-
+ static struct snd_rawmidi_ops pisnd_output_ops = {
+ .open = pisnd_output_open,
+ .close = pisnd_output_close,
+@@ -168,7 +167,11 @@ static struct snd_rawmidi_global_ops pis
+
+ static int pisnd_midi_init(struct snd_card *card)
+ {
+- int err = snd_rawmidi_new(card, "pisound MIDI", 0, 1, 1, &g_rmidi);
++ int err;
++
++ g_midi_output_substream = NULL;
++
++ err = snd_rawmidi_new(card, "pisound MIDI", 0, 1, 1, &g_rmidi);
+
+ if (err < 0) {
+ printe("snd_rawmidi_new failed: %d\n", err);
+@@ -209,7 +212,7 @@ static void pisnd_midi_uninit(void)
+ static void *g_recvData;
+ static pisnd_spi_recv_cb g_recvCallback;
+
+-#define FIFO_SIZE 512
++#define FIFO_SIZE 4096
+
+ static char g_serial_num[11];
+ static char g_id[25];
+@@ -231,6 +234,7 @@ static struct work_struct pisnd_work_pro
+
+ static void pisnd_work_handler(struct work_struct *work);
+
++static void spi_transfer(const uint8_t *txbuf, uint8_t *rxbuf, int len);
+ static uint16_t spi_transfer16(uint16_t val);
+
+ static int pisnd_init_workqueues(void)
+@@ -285,9 +289,6 @@ static unsigned long spilockflags;
+
+ static uint16_t spi_transfer16(uint16_t val)
+ {
+- int err;
+- struct spi_transfer transfer;
+- struct spi_message msg;
+ uint8_t txbuf[2];
+ uint8_t rxbuf[2];
+
+@@ -296,19 +297,38 @@ static uint16_t spi_transfer16(uint16_t
+ return 0;
+ }
+
++ txbuf[0] = val >> 8;
++ txbuf[1] = val & 0xff;
++
++ spi_transfer(txbuf, rxbuf, sizeof(txbuf));
++
++ printd("received: %02x%02x\n", rxbuf[0], rxbuf[1]);
++
++ return (rxbuf[0] << 8) | rxbuf[1];
++}
++
++static void spi_transfer(const uint8_t *txbuf, uint8_t *rxbuf, int len)
++{
++ int err;
++ struct spi_transfer transfer;
++ struct spi_message msg;
++
++ memset(rxbuf, 0, sizeof(txbuf));
++
++ if (!pisnd_spi_device) {
++ printe("pisnd_spi_device null, returning\n");
++ return;
++ }
++
+ spi_message_init(&msg);
+
+ memset(&transfer, 0, sizeof(transfer));
+- memset(&rxbuf, 0, sizeof(rxbuf));
+
+- txbuf[0] = val >> 8;
+- txbuf[1] = val & 0xff;
+-
+- transfer.tx_buf = &txbuf;
+- transfer.rx_buf = &rxbuf;
+- transfer.len = sizeof(txbuf);
+- transfer.speed_hz = 125000;
+- transfer.delay_usecs = 100;
++ transfer.tx_buf = txbuf;
++ transfer.rx_buf = rxbuf;
++ transfer.len = len;
++ transfer.speed_hz = 100000;
++ transfer.delay_usecs = 10;
+ spi_message_add_tail(&transfer, &msg);
+
+ spin_lock_irqsave(&spilock, spilockflags);
+@@ -317,13 +337,10 @@ static uint16_t spi_transfer16(uint16_t
+
+ if (err < 0) {
+ printe("spi_sync error %d\n", err);
+- return 0;
++ return;
+ }
+
+- printd("received: %02x%02x\n", rxbuf[0], rxbuf[1]);
+ printd("hasMore %d\n", pisnd_spi_has_more());
+-
+- return (rxbuf[0] << 8) | rxbuf[1];
+ }
+
+ static int spi_read_bytes(char *dst, size_t length, uint8_t *bytesRead)
+@@ -335,7 +352,7 @@ static int spi_read_bytes(char *dst, siz
+ memset(dst, 0, length);
+ *bytesRead = 0;
+
+- rx = spi_transfer16(0);
++ rx = spi_transfer16(0);
+ if (!(rx >> 8))
+ return -EINVAL;
+
+@@ -388,35 +405,90 @@ static struct spi_device *pisnd_spi_find
+
+ static void pisnd_work_handler(struct work_struct *work)
+ {
+- uint16_t rx;
+- uint16_t tx;
++ enum { TRANSFER_SIZE = 4 };
++ enum { PISOUND_OUTPUT_BUFFER_SIZE = 128 };
++ enum { MIDI_BYTES_PER_SECOND = 3125 };
++ int out_buffer_used = 0;
++ unsigned long now;
+ uint8_t val;
++ uint8_t txbuf[TRANSFER_SIZE];
++ uint8_t rxbuf[TRANSFER_SIZE];
++ uint8_t midibuf[TRANSFER_SIZE];
++ int i, n;
++ bool had_data;
++
++ unsigned long last_transfer_at = jiffies;
+
+ if (work == &pisnd_work_process) {
+ if (pisnd_spi_device == NULL)
+ return;
+
+ do {
+- val = 0;
+- tx = 0;
++ if (g_midi_output_substream &&
++ kfifo_avail(&spi_fifo_out) >= sizeof(midibuf)) {
+
+- if (g_ledFlashDurationChanged) {
+- tx = 0xf000 | g_ledFlashDuration;
+- g_ledFlashDuration = 0;
+- g_ledFlashDurationChanged = false;
+- } else if (kfifo_get(&spi_fifo_out, &val)) {
+- tx = 0x0f00 | val;
++ n = snd_rawmidi_transmit_peek(
++ g_midi_output_substream,
++ midibuf, sizeof(midibuf)
++ );
++
++ if (n > 0) {
++ for (i = 0; i < n; ++i)
++ kfifo_put(
++ &spi_fifo_out,
++ midibuf[i]
++ );
++ snd_rawmidi_transmit_ack(
++ g_midi_output_substream,
++ i
++ );
++ }
+ }
+
+- rx = spi_transfer16(tx);
++ had_data = false;
++ memset(txbuf, 0, sizeof(txbuf));
++ for (i = 0; i < sizeof(txbuf) &&
++ out_buffer_used < PISOUND_OUTPUT_BUFFER_SIZE;
++ i += 2) {
++
++ val = 0;
++
++ if (g_ledFlashDurationChanged) {
++ txbuf[i+0] = 0xf0;
++ txbuf[i+1] = g_ledFlashDuration;
++ g_ledFlashDuration = 0;
++ g_ledFlashDurationChanged = false;
++ } else if (kfifo_get(&spi_fifo_out, &val)) {
++ txbuf[i+0] = 0x0f;
++ txbuf[i+1] = val;
++ ++out_buffer_used;
++ }
++ }
+
+- if (rx & 0xff00) {
+- kfifo_put(&spi_fifo_in, rx & 0xff);
+- if (kfifo_len(&spi_fifo_in) > 16
+- && g_recvCallback)
+- g_recvCallback(g_recvData);
++ spi_transfer(txbuf, rxbuf, sizeof(txbuf));
++ /* Estimate the Pisound's MIDI output buffer usage, so
++ * that we don't overflow it. Space in the buffer should
++ * be becoming available at the UART MIDI byte transfer
++ * rate.
++ */
++ now = jiffies;
++ out_buffer_used -=
++ (MIDI_BYTES_PER_SECOND / HZ) /
++ (now - last_transfer_at);
++ if (out_buffer_used < 0)
++ out_buffer_used = 0;
++ last_transfer_at = now;
++
++ for (i = 0; i < sizeof(rxbuf); i += 2) {
++ if (rxbuf[i]) {
++ kfifo_put(&spi_fifo_in, rxbuf[i+1]);
++ if (kfifo_len(&spi_fifo_in) > 16 &&
++ g_recvCallback)
++ g_recvCallback(g_recvData);
++ had_data = true;
++ }
+ }
+- } while (rx != 0
++ } while (had_data
+ || !kfifo_is_empty(&spi_fifo_out)
+ || pisnd_spi_has_more()
+ || g_ledFlashDurationChanged
+@@ -492,7 +564,7 @@ static int spi_read_info(void)
+ if (!(tmp >> 8))
+ return -EINVAL;
+
+- count = tmp & 0xff;
++ count = tmp & 0xff;
+
+ for (i = 0; i < count; ++i) {
+ memset(buffer, 0, sizeof(buffer));
+@@ -628,10 +700,17 @@ static void pisnd_spi_flash_leds(uint8_t
+ pisnd_schedule_process(TASK_PROCESS);
+ }
+
+-static void pisnd_spi_send(uint8_t val)
++static void pisnd_spi_flush(void)
++{
++ while (!kfifo_is_empty(&spi_fifo_out)) {
++ pisnd_spi_start();
++ flush_workqueue(pisnd_workqueue);
++ }
++}
++
++static void pisnd_spi_start(void)
+ {
+- kfifo_put(&spi_fifo_out, val);
+- printd("schedule from spi_send\n");
++ printd("schedule from spi_start\n");
+ pisnd_schedule_process(TASK_PROCESS);
+ }
+
+@@ -765,7 +844,7 @@ static int pisnd_hw_params(
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+
+- /* pisound runs on fixed 32 clock counts per channel,
++ /* Pisound runs on fixed 32 clock counts per channel,
+ * as generated by the master ADC.
+ */
+ snd_soc_dai_set_bclk_ratio(cpu_dai, 32*2);
+@@ -786,8 +865,8 @@ static int pisnd_hw_params(
+ break;
+ case 96000:
+ gpiod_set_value(osr0, true);
+- gpiod_set_value(osr1, true);
+- gpiod_set_value(osr2, false);
++ gpiod_set_value(osr1, false);
++ gpiod_set_value(osr2, true);
+ break;
+ case 192000:
+ gpiod_set_value(osr0, true);
+@@ -1030,7 +1109,7 @@ static int pisnd_probe(struct platform_d
+ return ret;
+ }
+
+- printi("Detected pisound card:\n");
++ printi("Detected Pisound card:\n");
+ printi("\tSerial: %s\n", pisnd_spi_get_serial());
+ printi("\tVersion: %s\n", pisnd_spi_get_version());
+ printi("\tId: %s\n", pisnd_spi_get_id());
+@@ -1119,5 +1198,5 @@ static struct platform_driver pisnd_driv
+ module_platform_driver(pisnd_driver);
+
+ MODULE_AUTHOR("Giedrius Trainavicius <giedrius@blokas.io>");
+-MODULE_DESCRIPTION("ASoC Driver for pisound, http://blokas.io/pisound");
++MODULE_DESCRIPTION("ASoC Driver for Pisound, https://blokas.io/pisound");
+ MODULE_LICENSE("GPL v2");