aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/brcm2708/patches-4.9/0117-pisound-improvements.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/brcm2708/patches-4.9/0117-pisound-improvements.patch')
-rw-r--r--target/linux/brcm2708/patches-4.9/0117-pisound-improvements.patch294
1 files changed, 294 insertions, 0 deletions
diff --git a/target/linux/brcm2708/patches-4.9/0117-pisound-improvements.patch b/target/linux/brcm2708/patches-4.9/0117-pisound-improvements.patch
new file mode 100644
index 0000000000..f914bfc3ad
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.9/0117-pisound-improvements.patch
@@ -0,0 +1,294 @@
+From 8ed8e29b19dba95a7a6c2364c2bb32d926601713 Mon Sep 17 00:00:00 2001
+From: Giedrius Trainavicius <giedrius@blokas.io>
+Date: Thu, 5 Jan 2017 02:38:16 +0200
+Subject: [PATCH] pisound improvements:
+
+* Added a writable sysfs object to enable scripts / user space software
+to blink MIDI activity LEDs for variable duration.
+* Improved hw_param constraints setting.
+* Added compatibility with S16_LE sample format.
+* Exposed some simple placeholder volume controls, so the card appears
+in volumealsa widget.
+
+Signed-off-by: Giedrius Trainavicius <giedrius@blokas.io>
+---
+ sound/soc/bcm/pisound.c | 175 ++++++++++++++++++++++++++++++++++++++++++------
+ 1 file changed, 154 insertions(+), 21 deletions(-)
+
+--- a/sound/soc/bcm/pisound.c
++++ b/sound/soc/bcm/pisound.c
+@@ -36,6 +36,7 @@
+ #include <sound/jack.h>
+ #include <sound/rawmidi.h>
+ #include <sound/asequencer.h>
++#include <sound/control.h>
+
+ static int pisnd_spi_init(struct device *dev);
+ static void pisnd_spi_uninit(void);
+@@ -214,6 +215,9 @@ static char g_serial_num[11];
+ static char g_id[25];
+ static char g_version[5];
+
++static uint8_t g_ledFlashDuration;
++static bool g_ledFlashDurationChanged;
++
+ DEFINE_KFIFO(spi_fifo_in, uint8_t, FIFO_SIZE);
+ DEFINE_KFIFO(spi_fifo_out, uint8_t, FIFO_SIZE);
+
+@@ -396,8 +400,13 @@ static void pisnd_work_handler(struct wo
+ val = 0;
+ tx = 0;
+
+- if (kfifo_get(&spi_fifo_out, &val))
++ if (g_ledFlashDurationChanged) {
++ tx = 0xf000 | g_ledFlashDuration;
++ g_ledFlashDuration = 0;
++ g_ledFlashDurationChanged = false;
++ } else if (kfifo_get(&spi_fifo_out, &val)) {
+ tx = 0x0f00 | val;
++ }
+
+ rx = spi_transfer16(tx);
+
+@@ -410,6 +419,7 @@ static void pisnd_work_handler(struct wo
+ } while (rx != 0
+ || !kfifo_is_empty(&spi_fifo_out)
+ || pisnd_spi_has_more()
++ || g_ledFlashDurationChanged
+ );
+
+ if (!kfifo_is_empty(&spi_fifo_in) && g_recvCallback)
+@@ -569,7 +579,7 @@ static int pisnd_spi_init(struct device
+ }
+
+ /* Flash the LEDs. */
+- spi_transfer16(0xf000);
++ spi_transfer16(0xf008);
+
+ ret = pisnd_spi_gpio_irq_init(dev);
+ if (ret < 0) {
+@@ -610,6 +620,14 @@ static void pisnd_spi_uninit(void)
+ pisnd_spi_gpio_uninit();
+ }
+
++static void pisnd_spi_flash_leds(uint8_t duration)
++{
++ g_ledFlashDuration = duration;
++ g_ledFlashDurationChanged = true;
++ printd("schedule from spi_flash_leds\n");
++ pisnd_schedule_process(TASK_PROCESS);
++}
++
+ static void pisnd_spi_send(uint8_t val)
+ {
+ kfifo_put(&spi_fifo_out, val);
+@@ -658,6 +676,83 @@ static const struct of_device_id pisound
+ {},
+ };
+
++enum {
++ SWITCH = 0,
++ VOLUME = 1,
++};
++
++static int pisnd_ctl_info(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_info *uinfo)
++{
++ if (kcontrol->private_value == SWITCH) {
++ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
++ uinfo->count = 1;
++ uinfo->value.integer.min = 0;
++ uinfo->value.integer.max = 1;
++ return 0;
++ } else if (kcontrol->private_value == VOLUME) {
++ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
++ uinfo->count = 1;
++ uinfo->value.integer.min = 0;
++ uinfo->value.integer.max = 100;
++ return 0;
++ }
++ return -EINVAL;
++}
++
++static int pisnd_ctl_get(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ if (kcontrol->private_value == SWITCH) {
++ ucontrol->value.integer.value[0] = 1;
++ return 0;
++ } else if (kcontrol->private_value == VOLUME) {
++ ucontrol->value.integer.value[0] = 100;
++ return 0;
++ }
++
++ return -EINVAL;
++}
++
++static struct snd_kcontrol_new pisnd_ctl[] = {
++ {
++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .name = "PCM Playback Switch",
++ .index = 0,
++ .private_value = SWITCH,
++ .access = SNDRV_CTL_ELEM_ACCESS_READ,
++ .info = pisnd_ctl_info,
++ .get = pisnd_ctl_get,
++ },
++ {
++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .name = "PCM Playback Volume",
++ .index = 0,
++ .private_value = VOLUME,
++ .access = SNDRV_CTL_ELEM_ACCESS_READ,
++ .info = pisnd_ctl_info,
++ .get = pisnd_ctl_get,
++ },
++};
++
++static int pisnd_ctl_init(struct snd_card *card)
++{
++ int err, i;
++
++ for (i = 0; i < ARRAY_SIZE(pisnd_ctl); ++i) {
++ err = snd_ctl_add(card, snd_ctl_new1(&pisnd_ctl[i], NULL));
++ if (err < 0)
++ return err;
++ }
++
++ return 0;
++}
++
++static int pisnd_ctl_uninit(void)
++{
++ return 0;
++}
++
+ static struct gpio_desc *osr0, *osr1, *osr2;
+ static struct gpio_desc *reset;
+ static struct gpio_desc *button;
+@@ -667,6 +762,14 @@ static int pisnd_hw_params(
+ struct snd_pcm_hw_params *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,
++ * as generated by the master ADC.
++ */
++ snd_soc_dai_set_bclk_ratio(cpu_dai, 32*2);
++
+ printd("rate = %d\n", params_rate(params));
+ printd("ch = %d\n", params_channels(params));
+ printd("bits = %u\n",
+@@ -711,16 +814,6 @@ static struct snd_pcm_hw_constraint_list
+ .mask = 0,
+ };
+
+-static unsigned int sample_bits[] = {
+- 24, 32
+-};
+-
+-static struct snd_pcm_hw_constraint_list constraints_sample_bits = {
+- .count = ARRAY_SIZE(sample_bits),
+- .list = sample_bits,
+- .mask = 0,
+-};
+-
+ static int pisnd_startup(struct snd_pcm_substream *substream)
+ {
+ int err = snd_pcm_hw_constraint_list(
+@@ -733,11 +826,21 @@ static int pisnd_startup(struct snd_pcm_
+ if (err < 0)
+ return err;
+
+- err = snd_pcm_hw_constraint_list(
++ err = snd_pcm_hw_constraint_single(
+ substream->runtime,
+- 0,
+- SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
+- &constraints_sample_bits
++ SNDRV_PCM_HW_PARAM_CHANNELS,
++ 2
++ );
++
++ if (err < 0)
++ return err;
++
++ err = snd_pcm_hw_constraint_mask64(
++ substream->runtime,
++ SNDRV_PCM_HW_PARAM_FORMAT,
++ SNDRV_PCM_FMTBIT_S16_LE |
++ SNDRV_PCM_FMTBIT_S24_LE |
++ SNDRV_PCM_FMTBIT_S32_LE
+ );
+
+ if (err < 0)
+@@ -771,14 +874,23 @@ static int pisnd_card_probe(struct snd_s
+ {
+ int err = pisnd_midi_init(card->snd_card);
+
+- if (err < 0)
++ if (err < 0) {
+ printe("pisnd_midi_init failed: %d\n", err);
++ return err;
++ }
+
+- return err;
++ err = pisnd_ctl_init(card->snd_card);
++ if (err < 0) {
++ printe("pisnd_ctl_init failed: %d\n", err);
++ return err;
++ }
++
++ return 0;
+ }
+
+ static int pisnd_card_remove(struct snd_soc_card *card)
+ {
++ pisnd_ctl_uninit();
+ pisnd_midi_uninit();
+ return 0;
+ }
+@@ -870,17 +982,38 @@ static ssize_t pisnd_version_show(
+ return sprintf(buf, "%s\n", pisnd_spi_get_version());
+ }
+
++static ssize_t pisnd_led_store(
++ struct kobject *kobj,
++ struct kobj_attribute *attr,
++ const char *buf,
++ size_t length
++ )
++{
++ uint32_t timeout;
++ int err;
++
++ err = kstrtou32(buf, 10, &timeout);
++
++ if (err == 0 && timeout <= 255)
++ pisnd_spi_flash_leds(timeout);
++
++ return length;
++}
++
+ static struct kobj_attribute pisnd_serial_attribute =
+- __ATTR(serial, 0644, pisnd_serial_show, NULL);
++ __ATTR(serial, 0444, pisnd_serial_show, NULL);
+ static struct kobj_attribute pisnd_id_attribute =
+- __ATTR(id, 0644, pisnd_id_show, NULL);
++ __ATTR(id, 0444, pisnd_id_show, NULL);
+ static struct kobj_attribute pisnd_version_attribute =
+- __ATTR(version, 0644, pisnd_version_show, NULL);
++ __ATTR(version, 0444, pisnd_version_show, NULL);
++static struct kobj_attribute pisnd_led_attribute =
++ __ATTR(led, 0644, NULL, pisnd_led_store);
+
+ static struct attribute *attrs[] = {
+ &pisnd_serial_attribute.attr,
+ &pisnd_id_attribute.attr,
+ &pisnd_version_attribute.attr,
++ &pisnd_led_attribute.attr,
+ NULL
+ };
+