aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorScott Ling <sl@opensource.wolfsonmicro.com>2012-11-07 11:53:17 -0500
committerMark Brown <broonie@opensource.wolfsonmicro.com>2012-11-09 06:44:31 -0500
commit8f7d52affeb8341cbc602209b6f35eedb410d3ee (patch)
treec4938fee6396de621c8d0922bd9367d57da36392
parentf9baa0ccb2500be60c51aec6d1f3988dec0df3fe (diff)
ASoC: wm0010: Split out the firmware file parsing from the boot
Move the firmware load and record parsing functionality out into a separate function from the boot function. Signed-off-by: Scott Ling <sl@opensource.wolfsonmicro.com> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
-rw-r--r--sound/soc/codecs/wm0010.c263
1 files changed, 146 insertions, 117 deletions
diff --git a/sound/soc/codecs/wm0010.c b/sound/soc/codecs/wm0010.c
index 5c1291748326..7576330044ba 100644
--- a/sound/soc/codecs/wm0010.c
+++ b/sound/soc/codecs/wm0010.c
@@ -332,24 +332,165 @@ static void byte_swap_64(u64 *data_in, u64 *data_out, u32 len)
332 data_out[i] = cpu_to_be64(le64_to_cpu(data_in[i])); 332 data_out[i] = cpu_to_be64(le64_to_cpu(data_in[i]));
333} 333}
334 334
335static int wm0010_boot(struct snd_soc_codec *codec) 335static int wm0010_firmware_load(char *name, struct snd_soc_codec *codec)
336{ 336{
337 struct spi_device *spi = to_spi_device(codec->dev); 337 struct spi_device *spi = to_spi_device(codec->dev);
338 struct wm0010_priv *wm0010 = snd_soc_codec_get_drvdata(codec); 338 struct wm0010_priv *wm0010 = snd_soc_codec_get_drvdata(codec);
339 unsigned long flags;
340 struct list_head xfer_list; 339 struct list_head xfer_list;
341 struct wm0010_boot_xfer *xfer; 340 struct wm0010_boot_xfer *xfer;
342 int ret; 341 int ret;
343 struct completion done; 342 struct completion done;
344 const struct firmware *fw; 343 const struct firmware *fw;
345 const struct dfw_binrec *rec; 344 const struct dfw_binrec *rec;
345 u64 *img;
346 u8 *out, dsp;
347 u32 len, offset;
348
349 INIT_LIST_HEAD(&xfer_list);
350
351 ret = request_firmware(&fw, name, codec->dev);
352 if (ret != 0) {
353 dev_err(codec->dev, "Failed to request application: %d\n",
354 ret);
355 return ret;
356 }
357
358 rec = (const struct dfw_binrec *)fw->data;
359 offset = 0;
360 dsp = rec->data[0];
361 wm0010->boot_failed = false;
362 BUG_ON(!list_empty(&xfer_list));
363 init_completion(&done);
364
365 /* First record should be INFO */
366 if (rec->command != DFW_CMD_INFO) {
367 dev_err(codec->dev, "First record not INFO\r\n");
368 ret = -EINVAL;
369 goto abort;
370 }
371
372 /* Check it's a DSP file */
373 if (dsp != DEVICE_ID_WM0010) {
374 dev_err(codec->dev, "Not a WM0010 firmware file.\r\n");
375 ret = -EINVAL;
376 goto abort;
377 }
378
379 /* Skip the info record as we don't need to send it */
380 offset += ((rec->length) + 8);
381 rec = (void *)&rec->data[rec->length];
382
383 while (offset < fw->size) {
384 dev_dbg(codec->dev,
385 "Packet: command %d, data length = 0x%x\r\n",
386 rec->command, rec->length);
387 len = rec->length + 8;
388
389 out = kzalloc(len, GFP_KERNEL);
390 if (!out) {
391 dev_err(codec->dev,
392 "Failed to allocate RX buffer\n");
393 ret = -ENOMEM;
394 goto abort1;
395 }
396
397 img = kzalloc(len, GFP_KERNEL);
398 if (!img) {
399 dev_err(codec->dev,
400 "Failed to allocate image buffer\n");
401 ret = -ENOMEM;
402 goto abort1;
403 }
404
405 byte_swap_64((u64 *)&rec->command, img, len);
406
407 xfer = kzalloc(sizeof(*xfer), GFP_KERNEL);
408 if (!xfer) {
409 dev_err(codec->dev, "Failed to allocate xfer\n");
410 ret = -ENOMEM;
411 goto abort1;
412 }
413
414 xfer->codec = codec;
415 list_add_tail(&xfer->list, &xfer_list);
416
417 spi_message_init(&xfer->m);
418 xfer->m.complete = wm0010_boot_xfer_complete;
419 xfer->m.context = xfer;
420 xfer->t.tx_buf = img;
421 xfer->t.rx_buf = out;
422 xfer->t.len = len;
423 xfer->t.bits_per_word = 8;
424
425 if (!wm0010->pll_running) {
426 xfer->t.speed_hz = wm0010->sysclk / 6;
427 } else {
428 xfer->t.speed_hz = wm0010->max_spi_freq;
429
430 if (wm0010->board_max_spi_speed &&
431 (wm0010->board_max_spi_speed < wm0010->max_spi_freq))
432 xfer->t.speed_hz = wm0010->board_max_spi_speed;
433 }
434
435 /* Store max usable spi frequency for later use */
436 wm0010->max_spi_freq = xfer->t.speed_hz;
437
438 spi_message_add_tail(&xfer->t, &xfer->m);
439
440 offset += ((rec->length) + 8);
441 rec = (void *)&rec->data[rec->length];
442
443 if (offset >= fw->size) {
444 dev_dbg(codec->dev, "All transfers scheduled\n");
445 xfer->done = &done;
446 }
447
448 ret = spi_async(spi, &xfer->m);
449 if (ret != 0) {
450 dev_err(codec->dev, "Write failed: %d\n", ret);
451 goto abort1;
452 }
453
454 if (wm0010->boot_failed) {
455 dev_dbg(codec->dev, "Boot fail!\n");
456 ret = -EINVAL;
457 goto abort1;
458 }
459 }
460
461 wait_for_completion(&done);
462
463 ret = 0;
464
465abort1:
466 while (!list_empty(&xfer_list)) {
467 xfer = list_first_entry(&xfer_list, struct wm0010_boot_xfer,
468 list);
469 kfree(xfer->t.rx_buf);
470 kfree(xfer->t.tx_buf);
471 list_del(&xfer->list);
472 kfree(xfer);
473 }
474
475abort:
476 release_firmware(fw);
477 return ret;
478}
479
480static int wm0010_boot(struct snd_soc_codec *codec)
481{
482 struct spi_device *spi = to_spi_device(codec->dev);
483 struct wm0010_priv *wm0010 = snd_soc_codec_get_drvdata(codec);
484 unsigned long flags;
485 int ret;
486 const struct firmware *fw;
346 struct spi_message m; 487 struct spi_message m;
347 struct spi_transfer t; 488 struct spi_transfer t;
348 struct dfw_pllrec pll_rec; 489 struct dfw_pllrec pll_rec;
349 u32 *img, *p; 490 u32 *img, *p;
350 u64 *img_swap; 491 u64 *img_swap;
351 u8 *out; 492 u8 *out;
352 u32 len, offset; 493 u32 len;
353 int i; 494 int i;
354 495
355 spin_lock_irqsave(&wm0010->irq_lock, flags); 496 spin_lock_irqsave(&wm0010->irq_lock, flags);
@@ -363,8 +504,6 @@ static int wm0010_boot(struct snd_soc_codec *codec)
363 goto err; 504 goto err;
364 } 505 }
365 506
366 INIT_LIST_HEAD(&xfer_list);
367
368 mutex_lock(&wm0010->lock); 507 mutex_lock(&wm0010->lock);
369 wm0010->pll_running = false; 508 wm0010->pll_running = false;
370 509
@@ -533,109 +672,10 @@ static int wm0010_boot(struct snd_soc_codec *codec)
533 } else 672 } else
534 dev_dbg(codec->dev, "Not enabling DSP PLL."); 673 dev_dbg(codec->dev, "Not enabling DSP PLL.");
535 674
536 ret = request_firmware(&fw, "wm0010.dfw", codec->dev); 675 ret = wm0010_firmware_load("wm0010.dfw", codec);
537 if (ret != 0) {
538 dev_err(codec->dev, "Failed to request application: %d\n",
539 ret);
540 goto abort;
541 }
542 676
543 rec = (const struct dfw_binrec *)fw->data; 677 if (ret != 0)
544 offset = 0;
545 wm0010->boot_failed = false;
546 BUG_ON(!list_empty(&xfer_list));
547 init_completion(&done);
548
549 /* First record should be INFO */
550 if (rec->command != DFW_CMD_INFO) {
551 dev_err(codec->dev, "First record not INFO\r\n");
552 goto abort;
553 }
554
555 /* Check it's a 0010 file */
556 if (rec->data[0] != DEVICE_ID_WM0010) {
557 dev_err(codec->dev, "Not a WM0010 firmware file.\r\n");
558 goto abort; 678 goto abort;
559 }
560
561 /* Skip the info record as we don't need to send it */
562 offset += ((rec->length) + 8);
563 rec = (void *)&rec->data[rec->length];
564
565 while (offset < fw->size) {
566 dev_dbg(codec->dev,
567 "Packet: command %d, data length = 0x%x\r\n",
568 rec->command, rec->length);
569 len = rec->length + 8;
570
571 out = kzalloc(len, GFP_KERNEL);
572 if (!out) {
573 dev_err(codec->dev,
574 "Failed to allocate RX buffer\n");
575 goto abort;
576 }
577
578 img_swap = kzalloc(len, GFP_KERNEL);
579 if (!img_swap) {
580 dev_err(codec->dev,
581 "Failed to allocate image buffer\n");
582 goto abort;
583 }
584
585 /* We need to re-order for 0010 */
586 byte_swap_64((u64 *)&rec->command, img_swap, len);
587
588 xfer = kzalloc(sizeof(*xfer), GFP_KERNEL);
589 if (!xfer) {
590 dev_err(codec->dev, "Failed to allocate xfer\n");
591 goto abort;
592 }
593
594 xfer->codec = codec;
595 list_add_tail(&xfer->list, &xfer_list);
596
597 spi_message_init(&xfer->m);
598 xfer->m.complete = wm0010_boot_xfer_complete;
599 xfer->m.context = xfer;
600 xfer->t.tx_buf = img_swap;
601 xfer->t.rx_buf = out;
602 xfer->t.len = len;
603 xfer->t.bits_per_word = 8;
604
605 if (!wm0010->pll_running) {
606 xfer->t.speed_hz = wm0010->sysclk / 6;
607 } else {
608 xfer->t.speed_hz = wm0010->max_spi_freq;
609
610 if (wm0010->board_max_spi_speed &&
611 (wm0010->board_max_spi_speed < wm0010->max_spi_freq))
612 xfer->t.speed_hz = wm0010->board_max_spi_speed;
613 }
614
615 /* Store max usable spi frequency for later use */
616 wm0010->max_spi_freq = xfer->t.speed_hz;
617
618 spi_message_add_tail(&xfer->t, &xfer->m);
619
620 offset += ((rec->length) + 8);
621 rec = (void *)&rec->data[rec->length];
622
623 if (offset >= fw->size) {
624 dev_dbg(codec->dev, "All transfers scheduled\n");
625 xfer->done = &done;
626 }
627
628 ret = spi_async(spi, &xfer->m);
629 if (ret != 0) {
630 dev_err(codec->dev, "Write failed: %d\n", ret);
631 goto abort;
632 }
633
634 if (wm0010->boot_failed)
635 goto abort;
636 }
637
638 wait_for_completion(&done);
639 679
640 spin_lock_irqsave(&wm0010->irq_lock, flags); 680 spin_lock_irqsave(&wm0010->irq_lock, flags);
641 wm0010->state = WM0010_FIRMWARE; 681 wm0010->state = WM0010_FIRMWARE;
@@ -643,17 +683,6 @@ static int wm0010_boot(struct snd_soc_codec *codec)
643 683
644 mutex_unlock(&wm0010->lock); 684 mutex_unlock(&wm0010->lock);
645 685
646 release_firmware(fw);
647
648 while (!list_empty(&xfer_list)) {
649 xfer = list_first_entry(&xfer_list, struct wm0010_boot_xfer,
650 list);
651 kfree(xfer->t.rx_buf);
652 kfree(xfer->t.tx_buf);
653 list_del(&xfer->list);
654 kfree(xfer);
655 }
656
657 return 0; 686 return 0;
658 687
659abort: 688abort: