]>
Commit | Line | Data |
---|---|---|
e359dc24 MF |
1 | /* |
2 | * Load Analog Devices SigmaStudio firmware files | |
3 | * | |
d48b088e | 4 | * Copyright 2009-2014 Analog Devices Inc. |
e359dc24 MF |
5 | * |
6 | * Licensed under the GPL-2 or later. | |
7 | */ | |
8 | ||
9 | #include <linux/crc32.h> | |
e359dc24 MF |
10 | #include <linux/firmware.h> |
11 | #include <linux/kernel.h> | |
12 | #include <linux/i2c.h> | |
38fd54ee | 13 | #include <linux/regmap.h> |
27c46a25 | 14 | #include <linux/module.h> |
d48b088e LPC |
15 | #include <linux/slab.h> |
16 | ||
a35daac7 | 17 | #include <sound/control.h> |
d48b088e | 18 | #include <sound/soc.h> |
40216ce7 LPC |
19 | |
20 | #include "sigmadsp.h" | |
e359dc24 | 21 | |
a4c1d7e6 LPC |
22 | #define SIGMA_MAGIC "ADISIGM" |
23 | ||
a35daac7 LPC |
24 | #define SIGMA_FW_CHUNK_TYPE_DATA 0 |
25 | #define SIGMA_FW_CHUNK_TYPE_CONTROL 1 | |
26 | #define SIGMA_FW_CHUNK_TYPE_SAMPLERATES 2 | |
27 | ||
28 | struct sigmadsp_control { | |
29 | struct list_head head; | |
30 | uint32_t samplerates; | |
31 | unsigned int addr; | |
32 | unsigned int num_bytes; | |
33 | const char *name; | |
34 | struct snd_kcontrol *kcontrol; | |
35 | bool cached; | |
36 | uint8_t cache[]; | |
37 | }; | |
38 | ||
d48b088e LPC |
39 | struct sigmadsp_data { |
40 | struct list_head head; | |
a35daac7 | 41 | uint32_t samplerates; |
d48b088e LPC |
42 | unsigned int addr; |
43 | unsigned int length; | |
44 | uint8_t data[]; | |
45 | }; | |
46 | ||
a35daac7 LPC |
47 | struct sigma_fw_chunk { |
48 | __le32 length; | |
49 | __le32 tag; | |
50 | __le32 samplerates; | |
51 | } __packed; | |
52 | ||
53 | struct sigma_fw_chunk_data { | |
54 | struct sigma_fw_chunk chunk; | |
55 | __le16 addr; | |
56 | uint8_t data[]; | |
57 | } __packed; | |
58 | ||
59 | struct sigma_fw_chunk_control { | |
60 | struct sigma_fw_chunk chunk; | |
61 | __le16 type; | |
62 | __le16 addr; | |
63 | __le16 num_bytes; | |
64 | const char name[]; | |
65 | } __packed; | |
66 | ||
67 | struct sigma_fw_chunk_samplerate { | |
68 | struct sigma_fw_chunk chunk; | |
69 | __le32 samplerates[]; | |
70 | } __packed; | |
71 | ||
a4c1d7e6 LPC |
72 | struct sigma_firmware_header { |
73 | unsigned char magic[7]; | |
74 | u8 version; | |
75 | __le32 crc; | |
76 | } __packed; | |
77 | ||
78 | enum { | |
79 | SIGMA_ACTION_WRITEXBYTES = 0, | |
80 | SIGMA_ACTION_WRITESINGLE, | |
81 | SIGMA_ACTION_WRITESAFELOAD, | |
a4c1d7e6 LPC |
82 | SIGMA_ACTION_END, |
83 | }; | |
84 | ||
d48b088e LPC |
85 | struct sigma_action { |
86 | u8 instr; | |
87 | u8 len_hi; | |
88 | __le16 len; | |
89 | __be16 addr; | |
90 | unsigned char payload[]; | |
91 | } __packed; | |
92 | ||
93 | static int sigmadsp_write(struct sigmadsp *sigmadsp, unsigned int addr, | |
94 | const uint8_t data[], size_t len) | |
95 | { | |
96 | return sigmadsp->write(sigmadsp->control_data, addr, data, len); | |
97 | } | |
98 | ||
a35daac7 LPC |
99 | static int sigmadsp_read(struct sigmadsp *sigmadsp, unsigned int addr, |
100 | uint8_t data[], size_t len) | |
101 | { | |
102 | return sigmadsp->read(sigmadsp->control_data, addr, data, len); | |
103 | } | |
104 | ||
105 | static int sigmadsp_ctrl_info(struct snd_kcontrol *kcontrol, | |
106 | struct snd_ctl_elem_info *info) | |
107 | { | |
108 | struct sigmadsp_control *ctrl = (void *)kcontrol->private_value; | |
109 | ||
110 | info->type = SNDRV_CTL_ELEM_TYPE_BYTES; | |
111 | info->count = ctrl->num_bytes; | |
112 | ||
113 | return 0; | |
114 | } | |
115 | ||
116 | static int sigmadsp_ctrl_write(struct sigmadsp *sigmadsp, | |
117 | struct sigmadsp_control *ctrl, void *data) | |
118 | { | |
119 | /* safeload loads up to 20 bytes in a atomic operation */ | |
120 | if (ctrl->num_bytes > 4 && ctrl->num_bytes <= 20 && sigmadsp->ops && | |
121 | sigmadsp->ops->safeload) | |
122 | return sigmadsp->ops->safeload(sigmadsp, ctrl->addr, data, | |
123 | ctrl->num_bytes); | |
124 | else | |
125 | return sigmadsp_write(sigmadsp, ctrl->addr, data, | |
126 | ctrl->num_bytes); | |
127 | } | |
128 | ||
129 | static int sigmadsp_ctrl_put(struct snd_kcontrol *kcontrol, | |
130 | struct snd_ctl_elem_value *ucontrol) | |
131 | { | |
132 | struct sigmadsp_control *ctrl = (void *)kcontrol->private_value; | |
133 | struct sigmadsp *sigmadsp = snd_kcontrol_chip(kcontrol); | |
134 | uint8_t *data; | |
135 | int ret = 0; | |
136 | ||
137 | mutex_lock(&sigmadsp->lock); | |
138 | ||
139 | data = ucontrol->value.bytes.data; | |
140 | ||
141 | if (!(kcontrol->vd[0].access & SNDRV_CTL_ELEM_ACCESS_INACTIVE)) | |
142 | ret = sigmadsp_ctrl_write(sigmadsp, ctrl, data); | |
143 | ||
144 | if (ret == 0) { | |
145 | memcpy(ctrl->cache, data, ctrl->num_bytes); | |
146 | ctrl->cached = true; | |
147 | } | |
148 | ||
149 | mutex_unlock(&sigmadsp->lock); | |
150 | ||
151 | return ret; | |
152 | } | |
153 | ||
154 | static int sigmadsp_ctrl_get(struct snd_kcontrol *kcontrol, | |
155 | struct snd_ctl_elem_value *ucontrol) | |
156 | { | |
157 | struct sigmadsp_control *ctrl = (void *)kcontrol->private_value; | |
158 | struct sigmadsp *sigmadsp = snd_kcontrol_chip(kcontrol); | |
159 | int ret = 0; | |
160 | ||
161 | mutex_lock(&sigmadsp->lock); | |
162 | ||
163 | if (!ctrl->cached) { | |
164 | ret = sigmadsp_read(sigmadsp, ctrl->addr, ctrl->cache, | |
165 | ctrl->num_bytes); | |
166 | } | |
167 | ||
168 | if (ret == 0) { | |
169 | ctrl->cached = true; | |
170 | memcpy(ucontrol->value.bytes.data, ctrl->cache, | |
171 | ctrl->num_bytes); | |
172 | } | |
173 | ||
174 | mutex_unlock(&sigmadsp->lock); | |
175 | ||
176 | return ret; | |
177 | } | |
178 | ||
179 | static void sigmadsp_control_free(struct snd_kcontrol *kcontrol) | |
180 | { | |
181 | struct sigmadsp_control *ctrl = (void *)kcontrol->private_value; | |
182 | ||
183 | ctrl->kcontrol = NULL; | |
184 | } | |
185 | ||
186 | static bool sigma_fw_validate_control_name(const char *name, unsigned int len) | |
187 | { | |
188 | unsigned int i; | |
189 | ||
190 | for (i = 0; i < len; i++) { | |
191 | /* Normal ASCII characters are valid */ | |
192 | if (name[i] < ' ' || name[i] > '~') | |
193 | return false; | |
194 | } | |
195 | ||
196 | return true; | |
197 | } | |
198 | ||
199 | static int sigma_fw_load_control(struct sigmadsp *sigmadsp, | |
200 | const struct sigma_fw_chunk *chunk, unsigned int length) | |
201 | { | |
202 | const struct sigma_fw_chunk_control *ctrl_chunk; | |
203 | struct sigmadsp_control *ctrl; | |
204 | unsigned int num_bytes; | |
205 | size_t name_len; | |
206 | char *name; | |
207 | int ret; | |
208 | ||
209 | if (length <= sizeof(*ctrl_chunk)) | |
210 | return -EINVAL; | |
211 | ||
212 | ctrl_chunk = (const struct sigma_fw_chunk_control *)chunk; | |
213 | ||
214 | name_len = length - sizeof(*ctrl_chunk); | |
215 | if (name_len >= SNDRV_CTL_ELEM_ID_NAME_MAXLEN) | |
216 | name_len = SNDRV_CTL_ELEM_ID_NAME_MAXLEN - 1; | |
217 | ||
218 | /* Make sure there are no non-displayable characaters in the string */ | |
219 | if (!sigma_fw_validate_control_name(ctrl_chunk->name, name_len)) | |
220 | return -EINVAL; | |
221 | ||
222 | num_bytes = le16_to_cpu(ctrl_chunk->num_bytes); | |
223 | ctrl = kzalloc(sizeof(*ctrl) + num_bytes, GFP_KERNEL); | |
224 | if (!ctrl) | |
225 | return -ENOMEM; | |
226 | ||
227 | name = kzalloc(name_len + 1, GFP_KERNEL); | |
228 | if (!name) { | |
229 | ret = -ENOMEM; | |
230 | goto err_free_ctrl; | |
231 | } | |
232 | memcpy(name, ctrl_chunk->name, name_len); | |
233 | name[name_len] = '\0'; | |
234 | ctrl->name = name; | |
235 | ||
236 | ctrl->addr = le16_to_cpu(ctrl_chunk->addr); | |
237 | ctrl->num_bytes = num_bytes; | |
1fc10044 | 238 | ctrl->samplerates = le32_to_cpu(chunk->samplerates); |
a35daac7 LPC |
239 | |
240 | list_add_tail(&ctrl->head, &sigmadsp->ctrl_list); | |
241 | ||
242 | return 0; | |
243 | ||
244 | err_free_ctrl: | |
245 | kfree(ctrl); | |
246 | ||
247 | return ret; | |
248 | } | |
249 | ||
250 | static int sigma_fw_load_data(struct sigmadsp *sigmadsp, | |
251 | const struct sigma_fw_chunk *chunk, unsigned int length) | |
252 | { | |
253 | const struct sigma_fw_chunk_data *data_chunk; | |
254 | struct sigmadsp_data *data; | |
255 | ||
256 | if (length <= sizeof(*data_chunk)) | |
257 | return -EINVAL; | |
258 | ||
259 | data_chunk = (struct sigma_fw_chunk_data *)chunk; | |
260 | ||
261 | length -= sizeof(*data_chunk); | |
262 | ||
263 | data = kzalloc(sizeof(*data) + length, GFP_KERNEL); | |
264 | if (!data) | |
265 | return -ENOMEM; | |
266 | ||
267 | data->addr = le16_to_cpu(data_chunk->addr); | |
268 | data->length = length; | |
1fc10044 | 269 | data->samplerates = le32_to_cpu(chunk->samplerates); |
a35daac7 LPC |
270 | memcpy(data->data, data_chunk->data, length); |
271 | list_add_tail(&data->head, &sigmadsp->data_list); | |
272 | ||
273 | return 0; | |
274 | } | |
275 | ||
276 | static int sigma_fw_load_samplerates(struct sigmadsp *sigmadsp, | |
277 | const struct sigma_fw_chunk *chunk, unsigned int length) | |
278 | { | |
279 | const struct sigma_fw_chunk_samplerate *rate_chunk; | |
280 | unsigned int num_rates; | |
281 | unsigned int *rates; | |
282 | unsigned int i; | |
283 | ||
284 | rate_chunk = (const struct sigma_fw_chunk_samplerate *)chunk; | |
285 | ||
286 | num_rates = (length - sizeof(*rate_chunk)) / sizeof(__le32); | |
287 | ||
288 | if (num_rates > 32 || num_rates == 0) | |
289 | return -EINVAL; | |
290 | ||
291 | /* We only allow one samplerates block per file */ | |
292 | if (sigmadsp->rate_constraints.count) | |
293 | return -EINVAL; | |
294 | ||
295 | rates = kcalloc(num_rates, sizeof(*rates), GFP_KERNEL); | |
296 | if (!rates) | |
297 | return -ENOMEM; | |
298 | ||
299 | for (i = 0; i < num_rates; i++) | |
300 | rates[i] = le32_to_cpu(rate_chunk->samplerates[i]); | |
301 | ||
302 | sigmadsp->rate_constraints.count = num_rates; | |
303 | sigmadsp->rate_constraints.list = rates; | |
304 | ||
305 | return 0; | |
306 | } | |
307 | ||
308 | static int sigmadsp_fw_load_v2(struct sigmadsp *sigmadsp, | |
309 | const struct firmware *fw) | |
310 | { | |
311 | struct sigma_fw_chunk *chunk; | |
312 | unsigned int length, pos; | |
313 | int ret; | |
314 | ||
315 | /* | |
316 | * Make sure that there is at least one chunk to avoid integer | |
317 | * underflows later on. Empty firmware is still valid though. | |
318 | */ | |
319 | if (fw->size < sizeof(*chunk) + sizeof(struct sigma_firmware_header)) | |
320 | return 0; | |
321 | ||
322 | pos = sizeof(struct sigma_firmware_header); | |
323 | ||
324 | while (pos < fw->size - sizeof(*chunk)) { | |
325 | chunk = (struct sigma_fw_chunk *)(fw->data + pos); | |
326 | ||
327 | length = le32_to_cpu(chunk->length); | |
328 | ||
329 | if (length > fw->size - pos || length < sizeof(*chunk)) | |
330 | return -EINVAL; | |
331 | ||
1fc10044 | 332 | switch (le32_to_cpu(chunk->tag)) { |
a35daac7 LPC |
333 | case SIGMA_FW_CHUNK_TYPE_DATA: |
334 | ret = sigma_fw_load_data(sigmadsp, chunk, length); | |
335 | break; | |
336 | case SIGMA_FW_CHUNK_TYPE_CONTROL: | |
337 | ret = sigma_fw_load_control(sigmadsp, chunk, length); | |
338 | break; | |
339 | case SIGMA_FW_CHUNK_TYPE_SAMPLERATES: | |
340 | ret = sigma_fw_load_samplerates(sigmadsp, chunk, length); | |
341 | break; | |
342 | default: | |
343 | dev_warn(sigmadsp->dev, "Unknown chunk type: %d\n", | |
344 | chunk->tag); | |
345 | ret = 0; | |
346 | break; | |
347 | } | |
348 | ||
349 | if (ret) | |
350 | return ret; | |
351 | ||
352 | /* | |
353 | * This can not overflow since if length is larger than the | |
354 | * maximum firmware size (0x4000000) we'll error out earilier. | |
355 | */ | |
356 | pos += ALIGN(length, sizeof(__le32)); | |
357 | } | |
358 | ||
359 | return 0; | |
360 | } | |
361 | ||
a4c1d7e6 LPC |
362 | static inline u32 sigma_action_len(struct sigma_action *sa) |
363 | { | |
364 | return (sa->len_hi << 16) | le16_to_cpu(sa->len); | |
365 | } | |
366 | ||
4f718a29 LPC |
367 | static size_t sigma_action_size(struct sigma_action *sa) |
368 | { | |
369 | size_t payload = 0; | |
370 | ||
371 | switch (sa->instr) { | |
372 | case SIGMA_ACTION_WRITEXBYTES: | |
373 | case SIGMA_ACTION_WRITESINGLE: | |
374 | case SIGMA_ACTION_WRITESAFELOAD: | |
375 | payload = sigma_action_len(sa); | |
376 | break; | |
377 | default: | |
378 | break; | |
379 | } | |
380 | ||
381 | payload = ALIGN(payload, 2); | |
382 | ||
383 | return payload + sizeof(struct sigma_action); | |
384 | } | |
385 | ||
386 | /* | |
387 | * Returns a negative error value in case of an error, 0 if processing of | |
388 | * the firmware should be stopped after this action, 1 otherwise. | |
389 | */ | |
d48b088e LPC |
390 | static int process_sigma_action(struct sigmadsp *sigmadsp, |
391 | struct sigma_action *sa) | |
e359dc24 | 392 | { |
e359dc24 | 393 | size_t len = sigma_action_len(sa); |
d48b088e | 394 | struct sigmadsp_data *data; |
e359dc24 MF |
395 | |
396 | pr_debug("%s: instr:%i addr:%#x len:%zu\n", __func__, | |
397 | sa->instr, sa->addr, len); | |
398 | ||
399 | switch (sa->instr) { | |
400 | case SIGMA_ACTION_WRITEXBYTES: | |
401 | case SIGMA_ACTION_WRITESINGLE: | |
402 | case SIGMA_ACTION_WRITESAFELOAD: | |
d48b088e | 403 | if (len < 3) |
e359dc24 | 404 | return -EINVAL; |
d48b088e LPC |
405 | |
406 | data = kzalloc(sizeof(*data) + len - 2, GFP_KERNEL); | |
407 | if (!data) | |
408 | return -ENOMEM; | |
409 | ||
410 | data->addr = be16_to_cpu(sa->addr); | |
411 | data->length = len - 2; | |
412 | memcpy(data->data, sa->payload, data->length); | |
413 | list_add_tail(&data->head, &sigmadsp->data_list); | |
e359dc24 | 414 | break; |
e359dc24 | 415 | case SIGMA_ACTION_END: |
4f718a29 | 416 | return 0; |
e359dc24 MF |
417 | default: |
418 | return -EINVAL; | |
419 | } | |
420 | ||
4f718a29 | 421 | return 1; |
e359dc24 MF |
422 | } |
423 | ||
d48b088e LPC |
424 | static int sigmadsp_fw_load_v1(struct sigmadsp *sigmadsp, |
425 | const struct firmware *fw) | |
e359dc24 | 426 | { |
4f718a29 | 427 | struct sigma_action *sa; |
d48b088e | 428 | size_t size, pos; |
4f718a29 LPC |
429 | int ret; |
430 | ||
d48b088e LPC |
431 | pos = sizeof(struct sigma_firmware_header); |
432 | ||
433 | while (pos + sizeof(*sa) <= fw->size) { | |
434 | sa = (struct sigma_action *)(fw->data + pos); | |
4f718a29 LPC |
435 | |
436 | size = sigma_action_size(sa); | |
d48b088e LPC |
437 | pos += size; |
438 | if (pos > fw->size || size == 0) | |
4f718a29 LPC |
439 | break; |
440 | ||
d48b088e | 441 | ret = process_sigma_action(sigmadsp, sa); |
e359dc24 | 442 | |
e359dc24 | 443 | pr_debug("%s: action returned %i\n", __func__, ret); |
4f718a29 LPC |
444 | |
445 | if (ret <= 0) | |
e359dc24 MF |
446 | return ret; |
447 | } | |
4f718a29 | 448 | |
d48b088e | 449 | if (pos != fw->size) |
4f718a29 LPC |
450 | return -EINVAL; |
451 | ||
452 | return 0; | |
e359dc24 MF |
453 | } |
454 | ||
d48b088e | 455 | static void sigmadsp_firmware_release(struct sigmadsp *sigmadsp) |
e359dc24 | 456 | { |
a35daac7 | 457 | struct sigmadsp_control *ctrl, *_ctrl; |
d48b088e LPC |
458 | struct sigmadsp_data *data, *_data; |
459 | ||
a35daac7 LPC |
460 | list_for_each_entry_safe(ctrl, _ctrl, &sigmadsp->ctrl_list, head) { |
461 | kfree(ctrl->name); | |
462 | kfree(ctrl); | |
463 | } | |
464 | ||
d48b088e LPC |
465 | list_for_each_entry_safe(data, _data, &sigmadsp->data_list, head) |
466 | kfree(data); | |
467 | ||
a35daac7 | 468 | INIT_LIST_HEAD(&sigmadsp->ctrl_list); |
d48b088e LPC |
469 | INIT_LIST_HEAD(&sigmadsp->data_list); |
470 | } | |
471 | ||
472 | static void devm_sigmadsp_release(struct device *dev, void *res) | |
473 | { | |
474 | sigmadsp_firmware_release((struct sigmadsp *)res); | |
475 | } | |
476 | ||
477 | static int sigmadsp_firmware_load(struct sigmadsp *sigmadsp, const char *name) | |
478 | { | |
479 | const struct sigma_firmware_header *ssfw_head; | |
e359dc24 | 480 | const struct firmware *fw; |
d48b088e | 481 | int ret; |
e359dc24 MF |
482 | u32 crc; |
483 | ||
e359dc24 | 484 | /* first load the blob */ |
d48b088e | 485 | ret = request_firmware(&fw, name, sigmadsp->dev); |
e359dc24 MF |
486 | if (ret) { |
487 | pr_debug("%s: request_firmware() failed with %i\n", __func__, ret); | |
d48b088e | 488 | goto done; |
e359dc24 | 489 | } |
e359dc24 MF |
490 | |
491 | /* then verify the header */ | |
492 | ret = -EINVAL; | |
4f718a29 LPC |
493 | |
494 | /* | |
495 | * Reject too small or unreasonable large files. The upper limit has been | |
496 | * chosen a bit arbitrarily, but it should be enough for all practical | |
497 | * purposes and having the limit makes it easier to avoid integer | |
498 | * overflows later in the loading process. | |
499 | */ | |
48afc527 | 500 | if (fw->size < sizeof(*ssfw_head) || fw->size >= 0x4000000) { |
d48b088e | 501 | dev_err(sigmadsp->dev, "Failed to load firmware: Invalid size\n"); |
e359dc24 | 502 | goto done; |
48afc527 | 503 | } |
e359dc24 MF |
504 | |
505 | ssfw_head = (void *)fw->data; | |
48afc527 | 506 | if (memcmp(ssfw_head->magic, SIGMA_MAGIC, ARRAY_SIZE(ssfw_head->magic))) { |
d48b088e | 507 | dev_err(sigmadsp->dev, "Failed to load firmware: Invalid magic\n"); |
50c0f21b LPC |
508 | goto done; |
509 | } | |
510 | ||
c56935bd LPC |
511 | crc = crc32(0, fw->data + sizeof(*ssfw_head), |
512 | fw->size - sizeof(*ssfw_head)); | |
e359dc24 | 513 | pr_debug("%s: crc=%x\n", __func__, crc); |
48afc527 | 514 | if (crc != le32_to_cpu(ssfw_head->crc)) { |
d48b088e | 515 | dev_err(sigmadsp->dev, "Failed to load firmware: Wrong crc checksum: expected %x got %x\n", |
48afc527 | 516 | le32_to_cpu(ssfw_head->crc), crc); |
e359dc24 | 517 | goto done; |
48afc527 | 518 | } |
e359dc24 | 519 | |
d48b088e LPC |
520 | switch (ssfw_head->version) { |
521 | case 1: | |
522 | ret = sigmadsp_fw_load_v1(sigmadsp, fw); | |
523 | break; | |
a35daac7 LPC |
524 | case 2: |
525 | ret = sigmadsp_fw_load_v2(sigmadsp, fw); | |
526 | break; | |
d48b088e LPC |
527 | default: |
528 | dev_err(sigmadsp->dev, | |
a35daac7 | 529 | "Failed to load firmware: Invalid version %d. Supported firmware versions: 1, 2\n", |
d48b088e LPC |
530 | ssfw_head->version); |
531 | ret = -EINVAL; | |
532 | break; | |
533 | } | |
e359dc24 | 534 | |
d48b088e LPC |
535 | if (ret) |
536 | sigmadsp_firmware_release(sigmadsp); | |
e359dc24 | 537 | |
d48b088e | 538 | done: |
e359dc24 MF |
539 | release_firmware(fw); |
540 | ||
d48b088e LPC |
541 | return ret; |
542 | } | |
543 | ||
544 | static int sigmadsp_init(struct sigmadsp *sigmadsp, struct device *dev, | |
545 | const struct sigmadsp_ops *ops, const char *firmware_name) | |
546 | { | |
547 | sigmadsp->ops = ops; | |
548 | sigmadsp->dev = dev; | |
549 | ||
a35daac7 | 550 | INIT_LIST_HEAD(&sigmadsp->ctrl_list); |
d48b088e | 551 | INIT_LIST_HEAD(&sigmadsp->data_list); |
a35daac7 | 552 | mutex_init(&sigmadsp->lock); |
d48b088e LPC |
553 | |
554 | return sigmadsp_firmware_load(sigmadsp, firmware_name); | |
555 | } | |
556 | ||
557 | /** | |
558 | * devm_sigmadsp_init() - Initialize SigmaDSP instance | |
559 | * @dev: The parent device | |
560 | * @ops: The sigmadsp_ops to use for this instance | |
561 | * @firmware_name: Name of the firmware file to load | |
562 | * | |
563 | * Allocates a SigmaDSP instance and loads the specified firmware file. | |
564 | * | |
565 | * Returns a pointer to a struct sigmadsp on success, or a PTR_ERR() on error. | |
566 | */ | |
567 | struct sigmadsp *devm_sigmadsp_init(struct device *dev, | |
568 | const struct sigmadsp_ops *ops, const char *firmware_name) | |
569 | { | |
570 | struct sigmadsp *sigmadsp; | |
571 | int ret; | |
572 | ||
573 | sigmadsp = devres_alloc(devm_sigmadsp_release, sizeof(*sigmadsp), | |
574 | GFP_KERNEL); | |
575 | if (!sigmadsp) | |
576 | return ERR_PTR(-ENOMEM); | |
577 | ||
578 | ret = sigmadsp_init(sigmadsp, dev, ops, firmware_name); | |
579 | if (ret) { | |
580 | devres_free(sigmadsp); | |
581 | return ERR_PTR(ret); | |
582 | } | |
583 | ||
584 | devres_add(dev, sigmadsp); | |
585 | ||
586 | return sigmadsp; | |
587 | } | |
588 | EXPORT_SYMBOL_GPL(devm_sigmadsp_init); | |
589 | ||
a35daac7 LPC |
590 | static int sigmadsp_rate_to_index(struct sigmadsp *sigmadsp, unsigned int rate) |
591 | { | |
592 | unsigned int i; | |
593 | ||
594 | for (i = 0; i < sigmadsp->rate_constraints.count; i++) { | |
595 | if (sigmadsp->rate_constraints.list[i] == rate) | |
596 | return i; | |
597 | } | |
598 | ||
599 | return -EINVAL; | |
600 | } | |
601 | ||
602 | static unsigned int sigmadsp_get_samplerate_mask(struct sigmadsp *sigmadsp, | |
603 | unsigned int samplerate) | |
604 | { | |
605 | int samplerate_index; | |
606 | ||
607 | if (samplerate == 0) | |
608 | return 0; | |
609 | ||
610 | if (sigmadsp->rate_constraints.count) { | |
611 | samplerate_index = sigmadsp_rate_to_index(sigmadsp, samplerate); | |
612 | if (samplerate_index < 0) | |
613 | return 0; | |
614 | ||
615 | return BIT(samplerate_index); | |
616 | } else { | |
617 | return ~0; | |
618 | } | |
619 | } | |
620 | ||
621 | static bool sigmadsp_samplerate_valid(unsigned int supported, | |
622 | unsigned int requested) | |
623 | { | |
624 | /* All samplerates are supported */ | |
625 | if (!supported) | |
626 | return true; | |
627 | ||
628 | return supported & requested; | |
629 | } | |
630 | ||
631 | static int sigmadsp_alloc_control(struct sigmadsp *sigmadsp, | |
632 | struct sigmadsp_control *ctrl, unsigned int samplerate_mask) | |
633 | { | |
634 | struct snd_kcontrol_new template; | |
635 | struct snd_kcontrol *kcontrol; | |
a35daac7 LPC |
636 | |
637 | memset(&template, 0, sizeof(template)); | |
638 | template.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | |
639 | template.name = ctrl->name; | |
640 | template.info = sigmadsp_ctrl_info; | |
641 | template.get = sigmadsp_ctrl_get; | |
642 | template.put = sigmadsp_ctrl_put; | |
643 | template.private_value = (unsigned long)ctrl; | |
644 | template.access = SNDRV_CTL_ELEM_ACCESS_READWRITE; | |
645 | if (!sigmadsp_samplerate_valid(ctrl->samplerates, samplerate_mask)) | |
646 | template.access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; | |
647 | ||
648 | kcontrol = snd_ctl_new1(&template, sigmadsp); | |
649 | if (!kcontrol) | |
650 | return -ENOMEM; | |
651 | ||
652 | kcontrol->private_free = sigmadsp_control_free; | |
653 | ctrl->kcontrol = kcontrol; | |
654 | ||
141f87d4 | 655 | return snd_ctl_add(sigmadsp->component->card->snd_card, kcontrol); |
a35daac7 LPC |
656 | } |
657 | ||
658 | static void sigmadsp_activate_ctrl(struct sigmadsp *sigmadsp, | |
659 | struct sigmadsp_control *ctrl, unsigned int samplerate_mask) | |
660 | { | |
661 | struct snd_card *card = sigmadsp->component->card->snd_card; | |
662 | struct snd_kcontrol_volatile *vd; | |
663 | struct snd_ctl_elem_id id; | |
d98123a7 DC |
664 | bool active; |
665 | bool changed = false; | |
a35daac7 LPC |
666 | |
667 | active = sigmadsp_samplerate_valid(ctrl->samplerates, samplerate_mask); | |
668 | ||
669 | down_write(&card->controls_rwsem); | |
670 | if (!ctrl->kcontrol) { | |
671 | up_write(&card->controls_rwsem); | |
672 | return; | |
673 | } | |
674 | ||
675 | id = ctrl->kcontrol->id; | |
676 | vd = &ctrl->kcontrol->vd[0]; | |
677 | if (active == (bool)(vd->access & SNDRV_CTL_ELEM_ACCESS_INACTIVE)) { | |
678 | vd->access ^= SNDRV_CTL_ELEM_ACCESS_INACTIVE; | |
679 | changed = true; | |
680 | } | |
681 | up_write(&card->controls_rwsem); | |
682 | ||
683 | if (active && changed) { | |
684 | mutex_lock(&sigmadsp->lock); | |
685 | if (ctrl->cached) | |
686 | sigmadsp_ctrl_write(sigmadsp, ctrl, ctrl->cache); | |
687 | mutex_unlock(&sigmadsp->lock); | |
688 | } | |
689 | ||
690 | if (changed) | |
691 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, &id); | |
692 | } | |
693 | ||
d48b088e LPC |
694 | /** |
695 | * sigmadsp_attach() - Attach a sigmadsp instance to a ASoC component | |
696 | * @sigmadsp: The sigmadsp instance to attach | |
697 | * @component: The component to attach to | |
698 | * | |
699 | * Typically called in the components probe callback. | |
700 | * | |
701 | * Note, once this function has been called the firmware must not be released | |
702 | * until after the ALSA snd_card that the component belongs to has been | |
703 | * disconnected, even if sigmadsp_attach() returns an error. | |
704 | */ | |
705 | int sigmadsp_attach(struct sigmadsp *sigmadsp, | |
706 | struct snd_soc_component *component) | |
707 | { | |
a35daac7 LPC |
708 | struct sigmadsp_control *ctrl; |
709 | unsigned int samplerate_mask; | |
710 | int ret; | |
711 | ||
d48b088e LPC |
712 | sigmadsp->component = component; |
713 | ||
a35daac7 LPC |
714 | samplerate_mask = sigmadsp_get_samplerate_mask(sigmadsp, |
715 | sigmadsp->current_samplerate); | |
716 | ||
717 | list_for_each_entry(ctrl, &sigmadsp->ctrl_list, head) { | |
718 | ret = sigmadsp_alloc_control(sigmadsp, ctrl, samplerate_mask); | |
719 | if (ret) | |
720 | return ret; | |
721 | } | |
722 | ||
d48b088e LPC |
723 | return 0; |
724 | } | |
725 | EXPORT_SYMBOL_GPL(sigmadsp_attach); | |
726 | ||
727 | /** | |
728 | * sigmadsp_setup() - Setup the DSP for the specified samplerate | |
729 | * @sigmadsp: The sigmadsp instance to configure | |
730 | * @samplerate: The samplerate the DSP should be configured for | |
731 | * | |
732 | * Loads the appropriate firmware program and parameter memory (if not already | |
733 | * loaded) and enables the controls for the specified samplerate. Any control | |
734 | * parameter changes that have been made previously will be restored. | |
735 | * | |
736 | * Returns 0 on success, a negative error code otherwise. | |
737 | */ | |
738 | int sigmadsp_setup(struct sigmadsp *sigmadsp, unsigned int samplerate) | |
739 | { | |
a35daac7 LPC |
740 | struct sigmadsp_control *ctrl; |
741 | unsigned int samplerate_mask; | |
d48b088e LPC |
742 | struct sigmadsp_data *data; |
743 | int ret; | |
744 | ||
745 | if (sigmadsp->current_samplerate == samplerate) | |
746 | return 0; | |
747 | ||
a35daac7 LPC |
748 | samplerate_mask = sigmadsp_get_samplerate_mask(sigmadsp, samplerate); |
749 | if (samplerate_mask == 0) | |
750 | return -EINVAL; | |
751 | ||
d48b088e | 752 | list_for_each_entry(data, &sigmadsp->data_list, head) { |
a35daac7 LPC |
753 | if (!sigmadsp_samplerate_valid(data->samplerates, |
754 | samplerate_mask)) | |
755 | continue; | |
d48b088e LPC |
756 | ret = sigmadsp_write(sigmadsp, data->addr, data->data, |
757 | data->length); | |
758 | if (ret) | |
759 | goto err; | |
760 | } | |
761 | ||
a35daac7 LPC |
762 | list_for_each_entry(ctrl, &sigmadsp->ctrl_list, head) |
763 | sigmadsp_activate_ctrl(sigmadsp, ctrl, samplerate_mask); | |
764 | ||
d48b088e LPC |
765 | sigmadsp->current_samplerate = samplerate; |
766 | ||
767 | return 0; | |
768 | err: | |
769 | sigmadsp_reset(sigmadsp); | |
e359dc24 MF |
770 | |
771 | return ret; | |
772 | } | |
d48b088e LPC |
773 | EXPORT_SYMBOL_GPL(sigmadsp_setup); |
774 | ||
775 | /** | |
776 | * sigmadsp_reset() - Notify the sigmadsp instance that the DSP has been reset | |
777 | * @sigmadsp: The sigmadsp instance to reset | |
778 | * | |
779 | * Should be called whenever the DSP has been reset and parameter and program | |
780 | * memory need to be re-loaded. | |
781 | */ | |
782 | void sigmadsp_reset(struct sigmadsp *sigmadsp) | |
783 | { | |
a35daac7 LPC |
784 | struct sigmadsp_control *ctrl; |
785 | ||
786 | list_for_each_entry(ctrl, &sigmadsp->ctrl_list, head) | |
787 | sigmadsp_activate_ctrl(sigmadsp, ctrl, false); | |
788 | ||
d48b088e LPC |
789 | sigmadsp->current_samplerate = 0; |
790 | } | |
791 | EXPORT_SYMBOL_GPL(sigmadsp_reset); | |
792 | ||
793 | /** | |
794 | * sigmadsp_restrict_params() - Applies DSP firmware specific constraints | |
795 | * @sigmadsp: The sigmadsp instance | |
796 | * @substream: The substream to restrict | |
797 | * | |
798 | * Applies samplerate constraints that may be required by the firmware Should | |
799 | * typically be called from the CODEC/component drivers startup callback. | |
800 | * | |
801 | * Returns 0 on success, a negative error code otherwise. | |
802 | */ | |
803 | int sigmadsp_restrict_params(struct sigmadsp *sigmadsp, | |
804 | struct snd_pcm_substream *substream) | |
805 | { | |
a35daac7 LPC |
806 | if (sigmadsp->rate_constraints.count == 0) |
807 | return 0; | |
808 | ||
809 | return snd_pcm_hw_constraint_list(substream->runtime, 0, | |
810 | SNDRV_PCM_HW_PARAM_RATE, &sigmadsp->rate_constraints); | |
d48b088e LPC |
811 | } |
812 | EXPORT_SYMBOL_GPL(sigmadsp_restrict_params); | |
38fd54ee | 813 | |
27c46a25 | 814 | MODULE_LICENSE("GPL"); |