0564-pisound-improvements-1778.patch 7.2 KB

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