Skip to content

Commit

Permalink
pisound improvements:
Browse files Browse the repository at this point in the history
* 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>
  • Loading branch information
gtrainavicius authored and popcornmix committed May 5, 2017
1 parent edf9dcf commit 38340f4
Showing 1 changed file with 154 additions and 21 deletions.
175 changes: 154 additions & 21 deletions sound/soc/bcm/pisound.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -396,8 +400,13 @@ static void pisnd_work_handler(struct work_struct *work)
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);

Expand All @@ -410,6 +419,7 @@ static void pisnd_work_handler(struct work_struct *work)
} while (rx != 0
|| !kfifo_is_empty(&spi_fifo_out)
|| pisnd_spi_has_more()
|| g_ledFlashDurationChanged
);

if (!kfifo_is_empty(&spi_fifo_in) && g_recvCallback)
Expand Down Expand Up @@ -569,7 +579,7 @@ static int pisnd_spi_init(struct device *dev)
}

/* Flash the LEDs. */
spi_transfer16(0xf000);
spi_transfer16(0xf008);

ret = pisnd_spi_gpio_irq_init(dev);
if (ret < 0) {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -658,6 +676,83 @@ static const struct of_device_id pisound_of_match[] = {
{},
};

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;
Expand All @@ -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",
Expand Down Expand Up @@ -711,16 +814,6 @@ static struct snd_pcm_hw_constraint_list constraints_rates = {
.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(
Expand All @@ -733,11 +826,21 @@ static int pisnd_startup(struct snd_pcm_substream *substream)
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)
Expand Down Expand Up @@ -771,14 +874,23 @@ static int pisnd_card_probe(struct snd_soc_card *card)
{
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;
}
Expand Down Expand Up @@ -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
};

Expand Down

0 comments on commit 38340f4

Please sign in to comment.