4b6c569de0c04ff682b700accd35a18a97c1b18e
[openwrt/openwrt.git] / target / linux / brcm2708 / patches-4.4 / 0564-pisound-improvements-1778.patch
1 From ed621cdfdf0a5acf35079208818c9648f44ec638 Mon Sep 17 00:00:00 2001
2 From: gtrainavicius <gtrainavicius@users.noreply.github.com>
3 Date: Thu, 5 Jan 2017 17:08:45 +0200
4 Subject: [PATCH] pisound improvements: (#1778)
5
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
11 in volumealsa widget.
12
13 Signed-off-by: Giedrius Trainavicius <giedrius@blokas.io>
14 ---
15 sound/soc/bcm/pisound.c | 175 ++++++++++++++++++++++++++++++++++++++++++------
16 1 file changed, 154 insertions(+), 21 deletions(-)
17
18 diff --git a/sound/soc/bcm/pisound.c b/sound/soc/bcm/pisound.c
19 index 30903fcf..d317eb9 100644
20 --- a/sound/soc/bcm/pisound.c
21 +++ b/sound/soc/bcm/pisound.c
22 @@ -36,6 +36,7 @@
23 #include <sound/jack.h>
24 #include <sound/rawmidi.h>
25 #include <sound/asequencer.h>
26 +#include <sound/control.h>
27
28 static int pisnd_spi_init(struct device *dev);
29 static void pisnd_spi_uninit(void);
30 @@ -214,6 +215,9 @@ static char g_serial_num[11];
31 static char g_id[25];
32 static char g_version[5];
33
34 +static uint8_t g_ledFlashDuration;
35 +static bool g_ledFlashDurationChanged;
36 +
37 DEFINE_KFIFO(spi_fifo_in, uint8_t, FIFO_SIZE);
38 DEFINE_KFIFO(spi_fifo_out, uint8_t, FIFO_SIZE);
39
40 @@ -396,8 +400,13 @@ static void pisnd_work_handler(struct work_struct *work)
41 val = 0;
42 tx = 0;
43
44 - if (kfifo_get(&spi_fifo_out, &val))
45 + if (g_ledFlashDurationChanged) {
46 + tx = 0xf000 | g_ledFlashDuration;
47 + g_ledFlashDuration = 0;
48 + g_ledFlashDurationChanged = false;
49 + } else if (kfifo_get(&spi_fifo_out, &val)) {
50 tx = 0x0f00 | val;
51 + }
52
53 rx = spi_transfer16(tx);
54
55 @@ -410,6 +419,7 @@ static void pisnd_work_handler(struct work_struct *work)
56 } while (rx != 0
57 || !kfifo_is_empty(&spi_fifo_out)
58 || pisnd_spi_has_more()
59 + || g_ledFlashDurationChanged
60 );
61
62 if (!kfifo_is_empty(&spi_fifo_in) && g_recvCallback)
63 @@ -569,7 +579,7 @@ static int pisnd_spi_init(struct device *dev)
64 }
65
66 /* Flash the LEDs. */
67 - spi_transfer16(0xf000);
68 + spi_transfer16(0xf008);
69
70 ret = pisnd_spi_gpio_irq_init(dev);
71 if (ret < 0) {
72 @@ -610,6 +620,14 @@ static void pisnd_spi_uninit(void)
73 pisnd_spi_gpio_uninit();
74 }
75
76 +static void pisnd_spi_flash_leds(uint8_t duration)
77 +{
78 + g_ledFlashDuration = duration;
79 + g_ledFlashDurationChanged = true;
80 + printd("schedule from spi_flash_leds\n");
81 + pisnd_schedule_process(TASK_PROCESS);
82 +}
83 +
84 static void pisnd_spi_send(uint8_t val)
85 {
86 kfifo_put(&spi_fifo_out, val);
87 @@ -658,6 +676,83 @@ static const struct of_device_id pisound_of_match[] = {
88 {},
89 };
90
91 +enum {
92 + SWITCH = 0,
93 + VOLUME = 1,
94 +};
95 +
96 +static int pisnd_ctl_info(struct snd_kcontrol *kcontrol,
97 + struct snd_ctl_elem_info *uinfo)
98 +{
99 + if (kcontrol->private_value == SWITCH) {
100 + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
101 + uinfo->count = 1;
102 + uinfo->value.integer.min = 0;
103 + uinfo->value.integer.max = 1;
104 + return 0;
105 + } else if (kcontrol->private_value == VOLUME) {
106 + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
107 + uinfo->count = 1;
108 + uinfo->value.integer.min = 0;
109 + uinfo->value.integer.max = 100;
110 + return 0;
111 + }
112 + return -EINVAL;
113 +}
114 +
115 +static int pisnd_ctl_get(struct snd_kcontrol *kcontrol,
116 + struct snd_ctl_elem_value *ucontrol)
117 +{
118 + if (kcontrol->private_value == SWITCH) {
119 + ucontrol->value.integer.value[0] = 1;
120 + return 0;
121 + } else if (kcontrol->private_value == VOLUME) {
122 + ucontrol->value.integer.value[0] = 100;
123 + return 0;
124 + }
125 +
126 + return -EINVAL;
127 +}
128 +
129 +static struct snd_kcontrol_new pisnd_ctl[] = {
130 + {
131 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
132 + .name = "PCM Playback Switch",
133 + .index = 0,
134 + .private_value = SWITCH,
135 + .access = SNDRV_CTL_ELEM_ACCESS_READ,
136 + .info = pisnd_ctl_info,
137 + .get = pisnd_ctl_get,
138 + },
139 + {
140 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
141 + .name = "PCM Playback Volume",
142 + .index = 0,
143 + .private_value = VOLUME,
144 + .access = SNDRV_CTL_ELEM_ACCESS_READ,
145 + .info = pisnd_ctl_info,
146 + .get = pisnd_ctl_get,
147 + },
148 +};
149 +
150 +static int pisnd_ctl_init(struct snd_card *card)
151 +{
152 + int err, i;
153 +
154 + for (i = 0; i < ARRAY_SIZE(pisnd_ctl); ++i) {
155 + err = snd_ctl_add(card, snd_ctl_new1(&pisnd_ctl[i], NULL));
156 + if (err < 0)
157 + return err;
158 + }
159 +
160 + return 0;
161 +}
162 +
163 +static int pisnd_ctl_uninit(void)
164 +{
165 + return 0;
166 +}
167 +
168 static struct gpio_desc *osr0, *osr1, *osr2;
169 static struct gpio_desc *reset;
170 static struct gpio_desc *button;
171 @@ -667,6 +762,14 @@ static int pisnd_hw_params(
172 struct snd_pcm_hw_params *params
173 )
174 {
175 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
176 + struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
177 +
178 + /* pisound runs on fixed 32 clock counts per channel,
179 + * as generated by the master ADC.
180 + */
181 + snd_soc_dai_set_bclk_ratio(cpu_dai, 32*2);
182 +
183 printd("rate = %d\n", params_rate(params));
184 printd("ch = %d\n", params_channels(params));
185 printd("bits = %u\n",
186 @@ -711,16 +814,6 @@ static struct snd_pcm_hw_constraint_list constraints_rates = {
187 .mask = 0,
188 };
189
190 -static unsigned int sample_bits[] = {
191 - 24, 32
192 -};
193 -
194 -static struct snd_pcm_hw_constraint_list constraints_sample_bits = {
195 - .count = ARRAY_SIZE(sample_bits),
196 - .list = sample_bits,
197 - .mask = 0,
198 -};
199 -
200 static int pisnd_startup(struct snd_pcm_substream *substream)
201 {
202 int err = snd_pcm_hw_constraint_list(
203 @@ -733,11 +826,21 @@ static int pisnd_startup(struct snd_pcm_substream *substream)
204 if (err < 0)
205 return err;
206
207 - err = snd_pcm_hw_constraint_list(
208 + err = snd_pcm_hw_constraint_single(
209 substream->runtime,
210 - 0,
211 - SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
212 - &constraints_sample_bits
213 + SNDRV_PCM_HW_PARAM_CHANNELS,
214 + 2
215 + );
216 +
217 + if (err < 0)
218 + return err;
219 +
220 + err = snd_pcm_hw_constraint_mask64(
221 + substream->runtime,
222 + SNDRV_PCM_HW_PARAM_FORMAT,
223 + SNDRV_PCM_FMTBIT_S16_LE |
224 + SNDRV_PCM_FMTBIT_S24_LE |
225 + SNDRV_PCM_FMTBIT_S32_LE
226 );
227
228 if (err < 0)
229 @@ -771,14 +874,23 @@ static int pisnd_card_probe(struct snd_soc_card *card)
230 {
231 int err = pisnd_midi_init(card->snd_card);
232
233 - if (err < 0)
234 + if (err < 0) {
235 printe("pisnd_midi_init failed: %d\n", err);
236 + return err;
237 + }
238
239 - return err;
240 + err = pisnd_ctl_init(card->snd_card);
241 + if (err < 0) {
242 + printe("pisnd_ctl_init failed: %d\n", err);
243 + return err;
244 + }
245 +
246 + return 0;
247 }
248
249 static int pisnd_card_remove(struct snd_soc_card *card)
250 {
251 + pisnd_ctl_uninit();
252 pisnd_midi_uninit();
253 return 0;
254 }
255 @@ -870,17 +982,38 @@ static ssize_t pisnd_version_show(
256 return sprintf(buf, "%s\n", pisnd_spi_get_version());
257 }
258
259 +static ssize_t pisnd_led_store(
260 + struct kobject *kobj,
261 + struct kobj_attribute *attr,
262 + const char *buf,
263 + size_t length
264 + )
265 +{
266 + uint32_t timeout;
267 + int err;
268 +
269 + err = kstrtou32(buf, 10, &timeout);
270 +
271 + if (err == 0 && timeout <= 255)
272 + pisnd_spi_flash_leds(timeout);
273 +
274 + return length;
275 +}
276 +
277 static struct kobj_attribute pisnd_serial_attribute =
278 - __ATTR(serial, 0644, pisnd_serial_show, NULL);
279 + __ATTR(serial, 0444, pisnd_serial_show, NULL);
280 static struct kobj_attribute pisnd_id_attribute =
281 - __ATTR(id, 0644, pisnd_id_show, NULL);
282 + __ATTR(id, 0444, pisnd_id_show, NULL);
283 static struct kobj_attribute pisnd_version_attribute =
284 - __ATTR(version, 0644, pisnd_version_show, NULL);
285 + __ATTR(version, 0444, pisnd_version_show, NULL);
286 +static struct kobj_attribute pisnd_led_attribute =
287 + __ATTR(led, 0644, NULL, pisnd_led_store);
288
289 static struct attribute *attrs[] = {
290 &pisnd_serial_attribute.attr,
291 &pisnd_id_attribute.attr,
292 &pisnd_version_attribute.attr,
293 + &pisnd_led_attribute.attr,
294 NULL
295 };
296
297 --
298 2.1.4
299