diff options
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.patch | 422 |
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"); |