diff options
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.patch | 294 |
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 + }; + |