1 From 811d783519254a955ccb7a43b1d8d3f2d29a9a79 Mon Sep 17 00:00:00 2001
2 From: Giedrius Trainavicius <giedrius@blokas.io>
3 Date: Thu, 5 Jan 2017 02:38:16 +0200
4 Subject: [PATCH] pisound improvements:
6 * Added a writable sysfs object to enable scripts / user space software
7 to blink MIDI activity LEDs for variable duration.
8 * Improved hw_param constraints setting.
9 * Added compatibility with S16_LE sample format.
10 * Exposed some simple placeholder volume controls, so the card appears
13 Signed-off-by: Giedrius Trainavicius <giedrius@blokas.io>
15 sound/soc/bcm/pisound.c | 175 ++++++++++++++++++++++++++++++++++++++++++------
16 1 file changed, 154 insertions(+), 21 deletions(-)
18 --- a/sound/soc/bcm/pisound.c
19 +++ b/sound/soc/bcm/pisound.c
21 #include <sound/jack.h>
22 #include <sound/rawmidi.h>
23 #include <sound/asequencer.h>
24 +#include <sound/control.h>
26 static int pisnd_spi_init(struct device *dev);
27 static void pisnd_spi_uninit(void);
28 @@ -214,6 +215,9 @@ static char g_serial_num[11];
30 static char g_version[5];
32 +static uint8_t g_ledFlashDuration;
33 +static bool g_ledFlashDurationChanged;
35 DEFINE_KFIFO(spi_fifo_in, uint8_t, FIFO_SIZE);
36 DEFINE_KFIFO(spi_fifo_out, uint8_t, FIFO_SIZE);
38 @@ -396,8 +400,13 @@ static void pisnd_work_handler(struct wo
42 - if (kfifo_get(&spi_fifo_out, &val))
43 + if (g_ledFlashDurationChanged) {
44 + tx = 0xf000 | g_ledFlashDuration;
45 + g_ledFlashDuration = 0;
46 + g_ledFlashDurationChanged = false;
47 + } else if (kfifo_get(&spi_fifo_out, &val)) {
51 rx = spi_transfer16(tx);
53 @@ -410,6 +419,7 @@ static void pisnd_work_handler(struct wo
55 || !kfifo_is_empty(&spi_fifo_out)
56 || pisnd_spi_has_more()
57 + || g_ledFlashDurationChanged
60 if (!kfifo_is_empty(&spi_fifo_in) && g_recvCallback)
61 @@ -569,7 +579,7 @@ static int pisnd_spi_init(struct device
65 - spi_transfer16(0xf000);
66 + spi_transfer16(0xf008);
68 ret = pisnd_spi_gpio_irq_init(dev);
70 @@ -610,6 +620,14 @@ static void pisnd_spi_uninit(void)
71 pisnd_spi_gpio_uninit();
74 +static void pisnd_spi_flash_leds(uint8_t duration)
76 + g_ledFlashDuration = duration;
77 + g_ledFlashDurationChanged = true;
78 + printd("schedule from spi_flash_leds\n");
79 + pisnd_schedule_process(TASK_PROCESS);
82 static void pisnd_spi_send(uint8_t val)
84 kfifo_put(&spi_fifo_out, val);
85 @@ -658,6 +676,83 @@ static const struct of_device_id pisound
94 +static int pisnd_ctl_info(struct snd_kcontrol *kcontrol,
95 + struct snd_ctl_elem_info *uinfo)
97 + if (kcontrol->private_value == SWITCH) {
98 + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
100 + uinfo->value.integer.min = 0;
101 + uinfo->value.integer.max = 1;
103 + } else if (kcontrol->private_value == VOLUME) {
104 + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
106 + uinfo->value.integer.min = 0;
107 + uinfo->value.integer.max = 100;
113 +static int pisnd_ctl_get(struct snd_kcontrol *kcontrol,
114 + struct snd_ctl_elem_value *ucontrol)
116 + if (kcontrol->private_value == SWITCH) {
117 + ucontrol->value.integer.value[0] = 1;
119 + } else if (kcontrol->private_value == VOLUME) {
120 + ucontrol->value.integer.value[0] = 100;
127 +static struct snd_kcontrol_new pisnd_ctl[] = {
129 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
130 + .name = "PCM Playback Switch",
132 + .private_value = SWITCH,
133 + .access = SNDRV_CTL_ELEM_ACCESS_READ,
134 + .info = pisnd_ctl_info,
135 + .get = pisnd_ctl_get,
138 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
139 + .name = "PCM Playback Volume",
141 + .private_value = VOLUME,
142 + .access = SNDRV_CTL_ELEM_ACCESS_READ,
143 + .info = pisnd_ctl_info,
144 + .get = pisnd_ctl_get,
148 +static int pisnd_ctl_init(struct snd_card *card)
152 + for (i = 0; i < ARRAY_SIZE(pisnd_ctl); ++i) {
153 + err = snd_ctl_add(card, snd_ctl_new1(&pisnd_ctl[i], NULL));
161 +static int pisnd_ctl_uninit(void)
166 static struct gpio_desc *osr0, *osr1, *osr2;
167 static struct gpio_desc *reset;
168 static struct gpio_desc *button;
169 @@ -667,6 +762,14 @@ static int pisnd_hw_params(
170 struct snd_pcm_hw_params *params
173 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
174 + struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
176 + /* pisound runs on fixed 32 clock counts per channel,
177 + * as generated by the master ADC.
179 + snd_soc_dai_set_bclk_ratio(cpu_dai, 32*2);
181 printd("rate = %d\n", params_rate(params));
182 printd("ch = %d\n", params_channels(params));
183 printd("bits = %u\n",
184 @@ -711,16 +814,6 @@ static struct snd_pcm_hw_constraint_list
188 -static unsigned int sample_bits[] = {
192 -static struct snd_pcm_hw_constraint_list constraints_sample_bits = {
193 - .count = ARRAY_SIZE(sample_bits),
194 - .list = sample_bits,
198 static int pisnd_startup(struct snd_pcm_substream *substream)
200 int err = snd_pcm_hw_constraint_list(
201 @@ -733,11 +826,21 @@ static int pisnd_startup(struct snd_pcm_
205 - err = snd_pcm_hw_constraint_list(
206 + err = snd_pcm_hw_constraint_single(
209 - SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
210 - &constraints_sample_bits
211 + SNDRV_PCM_HW_PARAM_CHANNELS,
218 + err = snd_pcm_hw_constraint_mask64(
219 + substream->runtime,
220 + SNDRV_PCM_HW_PARAM_FORMAT,
221 + SNDRV_PCM_FMTBIT_S16_LE |
222 + SNDRV_PCM_FMTBIT_S24_LE |
223 + SNDRV_PCM_FMTBIT_S32_LE
227 @@ -771,14 +874,23 @@ static int pisnd_card_probe(struct snd_s
229 int err = pisnd_midi_init(card->snd_card);
233 printe("pisnd_midi_init failed: %d\n", err);
238 + err = pisnd_ctl_init(card->snd_card);
240 + printe("pisnd_ctl_init failed: %d\n", err);
247 static int pisnd_card_remove(struct snd_soc_card *card)
249 + pisnd_ctl_uninit();
253 @@ -870,17 +982,38 @@ static ssize_t pisnd_version_show(
254 return sprintf(buf, "%s\n", pisnd_spi_get_version());
257 +static ssize_t pisnd_led_store(
258 + struct kobject *kobj,
259 + struct kobj_attribute *attr,
267 + err = kstrtou32(buf, 10, &timeout);
269 + if (err == 0 && timeout <= 255)
270 + pisnd_spi_flash_leds(timeout);
275 static struct kobj_attribute pisnd_serial_attribute =
276 - __ATTR(serial, 0644, pisnd_serial_show, NULL);
277 + __ATTR(serial, 0444, pisnd_serial_show, NULL);
278 static struct kobj_attribute pisnd_id_attribute =
279 - __ATTR(id, 0644, pisnd_id_show, NULL);
280 + __ATTR(id, 0444, pisnd_id_show, NULL);
281 static struct kobj_attribute pisnd_version_attribute =
282 - __ATTR(version, 0644, pisnd_version_show, NULL);
283 + __ATTR(version, 0444, pisnd_version_show, NULL);
284 +static struct kobj_attribute pisnd_led_attribute =
285 + __ATTR(led, 0644, NULL, pisnd_led_store);
287 static struct attribute *attrs[] = {
288 &pisnd_serial_attribute.attr,
289 &pisnd_id_attribute.attr,
290 &pisnd_version_attribute.attr,
291 + &pisnd_led_attribute.attr,