123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294 |
- From ed621cdfdf0a5acf35079208818c9648f44ec638 Mon Sep 17 00:00:00 2001
- From: gtrainavicius <gtrainavicius@users.noreply.github.com>
- Date: Thu, 5 Jan 2017 17:08:45 +0200
- Subject: [PATCH] pisound improvements: (#1778)
- * 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
- };
-
|