OSDN Git Service

ASoC: wm0010: Split out the firmware file parsing from the boot
authorScott Ling <sl@opensource.wolfsonmicro.com>
Wed, 7 Nov 2012 16:53:17 +0000 (16:53 +0000)
committerMark Brown <broonie@opensource.wolfsonmicro.com>
Fri, 9 Nov 2012 11:44:31 +0000 (11:44 +0000)
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>
sound/soc/codecs/wm0010.c

index 5c12917..7576330 100644 (file)
@@ -332,24 +332,165 @@ static void byte_swap_64(u64 *data_in, u64 *data_out, u32 len)
                data_out[i] = cpu_to_be64(le64_to_cpu(data_in[i]));
 }
 
-static int wm0010_boot(struct snd_soc_codec *codec)
+static int wm0010_firmware_load(char *name, struct snd_soc_codec *codec)
 {
        struct spi_device *spi = to_spi_device(codec->dev);
        struct wm0010_priv *wm0010 = snd_soc_codec_get_drvdata(codec);
-       unsigned long flags;
        struct list_head xfer_list;
        struct wm0010_boot_xfer *xfer;
        int ret;
        struct completion done;
        const struct firmware *fw;
        const struct dfw_binrec *rec;
+       u64 *img;
+       u8 *out, dsp;
+       u32 len, offset;
+
+       INIT_LIST_HEAD(&xfer_list);
+
+       ret = request_firmware(&fw, name, codec->dev);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to request application: %d\n",
+                       ret);
+               return ret;
+       }
+
+       rec = (const struct dfw_binrec *)fw->data;
+       offset = 0;
+       dsp = rec->data[0];
+       wm0010->boot_failed = false;
+       BUG_ON(!list_empty(&xfer_list));
+       init_completion(&done);
+
+       /* First record should be INFO */
+       if (rec->command != DFW_CMD_INFO) {
+               dev_err(codec->dev, "First record not INFO\r\n");
+               ret = -EINVAL;
+               goto abort;
+       }
+
+       /* Check it's a DSP file */
+       if (dsp != DEVICE_ID_WM0010) {
+               dev_err(codec->dev, "Not a WM0010 firmware file.\r\n");
+               ret = -EINVAL;
+               goto abort;
+       }
+
+       /* Skip the info record as we don't need to send it */
+       offset += ((rec->length) + 8);
+       rec = (void *)&rec->data[rec->length];
+
+       while (offset < fw->size) {
+               dev_dbg(codec->dev,
+                       "Packet: command %d, data length = 0x%x\r\n",
+                       rec->command, rec->length);
+               len = rec->length + 8;
+
+               out = kzalloc(len, GFP_KERNEL);
+               if (!out) {
+                       dev_err(codec->dev,
+                               "Failed to allocate RX buffer\n");
+                       ret = -ENOMEM;
+                       goto abort1;
+               }
+
+               img = kzalloc(len, GFP_KERNEL);
+               if (!img) {
+                       dev_err(codec->dev,
+                               "Failed to allocate image buffer\n");
+                       ret = -ENOMEM;
+                       goto abort1;
+               }
+
+               byte_swap_64((u64 *)&rec->command, img, len);
+
+               xfer = kzalloc(sizeof(*xfer), GFP_KERNEL);
+               if (!xfer) {
+                       dev_err(codec->dev, "Failed to allocate xfer\n");
+                       ret = -ENOMEM;
+                       goto abort1;
+               }
+
+               xfer->codec = codec;
+               list_add_tail(&xfer->list, &xfer_list);
+
+               spi_message_init(&xfer->m);
+               xfer->m.complete = wm0010_boot_xfer_complete;
+               xfer->m.context = xfer;
+               xfer->t.tx_buf = img;
+               xfer->t.rx_buf = out;
+               xfer->t.len = len;
+               xfer->t.bits_per_word = 8;
+
+               if (!wm0010->pll_running) {
+                       xfer->t.speed_hz = wm0010->sysclk / 6;
+               } else {
+                       xfer->t.speed_hz = wm0010->max_spi_freq;
+
+                       if (wm0010->board_max_spi_speed &&
+                          (wm0010->board_max_spi_speed < wm0010->max_spi_freq))
+                                       xfer->t.speed_hz = wm0010->board_max_spi_speed;
+               }
+
+               /* Store max usable spi frequency for later use */
+               wm0010->max_spi_freq = xfer->t.speed_hz;
+
+               spi_message_add_tail(&xfer->t, &xfer->m);
+
+               offset += ((rec->length) + 8);
+               rec = (void *)&rec->data[rec->length];
+
+               if (offset >= fw->size) {
+                       dev_dbg(codec->dev, "All transfers scheduled\n");
+                       xfer->done = &done;
+               }
+
+               ret = spi_async(spi, &xfer->m);
+               if (ret != 0) {
+                       dev_err(codec->dev, "Write failed: %d\n", ret);
+                       goto abort1;
+               }
+
+               if (wm0010->boot_failed) {
+                       dev_dbg(codec->dev, "Boot fail!\n");
+                       ret = -EINVAL;
+                       goto abort1;
+               }
+       }
+
+       wait_for_completion(&done);
+
+       ret = 0;
+
+abort1:
+       while (!list_empty(&xfer_list)) {
+               xfer = list_first_entry(&xfer_list, struct wm0010_boot_xfer,
+                                       list);
+               kfree(xfer->t.rx_buf);
+               kfree(xfer->t.tx_buf);
+               list_del(&xfer->list);
+               kfree(xfer);
+       }
+
+abort:
+       release_firmware(fw);
+       return ret;
+}
+
+static int wm0010_boot(struct snd_soc_codec *codec)
+{
+       struct spi_device *spi = to_spi_device(codec->dev);
+       struct wm0010_priv *wm0010 = snd_soc_codec_get_drvdata(codec);
+       unsigned long flags;
+       int ret;
+       const struct firmware *fw;
        struct spi_message m;
        struct spi_transfer t;
        struct dfw_pllrec pll_rec;
        u32 *img, *p;
        u64 *img_swap;
        u8 *out;
-       u32 len, offset;
+       u32 len;
        int i;
 
        spin_lock_irqsave(&wm0010->irq_lock, flags);
@@ -363,8 +504,6 @@ static int wm0010_boot(struct snd_soc_codec *codec)
                goto err;
        }
 
-       INIT_LIST_HEAD(&xfer_list);
-
        mutex_lock(&wm0010->lock);
        wm0010->pll_running = false;
 
@@ -533,109 +672,10 @@ static int wm0010_boot(struct snd_soc_codec *codec)
        } else
                dev_dbg(codec->dev, "Not enabling DSP PLL.");
 
-       ret = request_firmware(&fw, "wm0010.dfw", codec->dev);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to request application: %d\n",
-                       ret);
-               goto abort;
-       }
+       ret = wm0010_firmware_load("wm0010.dfw", codec);
 
-       rec = (const struct dfw_binrec *)fw->data;
-       offset = 0;
-       wm0010->boot_failed = false;
-       BUG_ON(!list_empty(&xfer_list));
-       init_completion(&done);
-
-       /* First record should be INFO */
-       if (rec->command != DFW_CMD_INFO) {
-               dev_err(codec->dev, "First record not INFO\r\n");
-               goto abort;
-       }
-
-       /* Check it's a 0010 file */
-       if (rec->data[0] != DEVICE_ID_WM0010) {
-               dev_err(codec->dev, "Not a WM0010 firmware file.\r\n");
+       if (ret != 0)
                goto abort;
-       }
-
-       /* Skip the info record as we don't need to send it */
-       offset += ((rec->length) + 8);
-       rec = (void *)&rec->data[rec->length];
-
-       while (offset < fw->size) {
-               dev_dbg(codec->dev,
-                       "Packet: command %d, data length = 0x%x\r\n",
-                       rec->command, rec->length);
-               len = rec->length + 8;
-
-               out = kzalloc(len, GFP_KERNEL);
-               if (!out) {
-                       dev_err(codec->dev,
-                               "Failed to allocate RX buffer\n");
-                       goto abort;
-               }
-
-               img_swap = kzalloc(len, GFP_KERNEL);
-               if (!img_swap) {
-                       dev_err(codec->dev,
-                               "Failed to allocate image buffer\n");
-                       goto abort;
-               }
-
-               /* We need to re-order for 0010 */
-               byte_swap_64((u64 *)&rec->command, img_swap, len);
-
-               xfer = kzalloc(sizeof(*xfer), GFP_KERNEL);
-               if (!xfer) {
-                       dev_err(codec->dev, "Failed to allocate xfer\n");
-                       goto abort;
-               }
-
-               xfer->codec = codec;
-               list_add_tail(&xfer->list, &xfer_list);
-
-               spi_message_init(&xfer->m);
-               xfer->m.complete = wm0010_boot_xfer_complete;
-               xfer->m.context = xfer;
-               xfer->t.tx_buf = img_swap;
-               xfer->t.rx_buf = out;
-               xfer->t.len = len;
-               xfer->t.bits_per_word = 8;
-
-               if (!wm0010->pll_running) {
-                       xfer->t.speed_hz = wm0010->sysclk / 6;
-               } else {
-                       xfer->t.speed_hz = wm0010->max_spi_freq;
-
-                       if (wm0010->board_max_spi_speed &&
-                          (wm0010->board_max_spi_speed < wm0010->max_spi_freq))
-                                       xfer->t.speed_hz = wm0010->board_max_spi_speed;
-               }
-
-               /* Store max usable spi frequency for later use */
-               wm0010->max_spi_freq = xfer->t.speed_hz;
-
-               spi_message_add_tail(&xfer->t, &xfer->m);
-
-               offset += ((rec->length) + 8);
-               rec = (void *)&rec->data[rec->length];
-
-               if (offset >= fw->size) {
-                       dev_dbg(codec->dev, "All transfers scheduled\n");
-                       xfer->done = &done;
-               }
-
-               ret = spi_async(spi, &xfer->m);
-               if (ret != 0) {
-                       dev_err(codec->dev, "Write failed: %d\n", ret);
-                       goto abort;
-               }
-
-               if (wm0010->boot_failed)
-                       goto abort;
-       }
-
-       wait_for_completion(&done);
 
        spin_lock_irqsave(&wm0010->irq_lock, flags);
        wm0010->state = WM0010_FIRMWARE;
@@ -643,17 +683,6 @@ static int wm0010_boot(struct snd_soc_codec *codec)
 
        mutex_unlock(&wm0010->lock);
 
-       release_firmware(fw);
-
-       while (!list_empty(&xfer_list)) {
-               xfer = list_first_entry(&xfer_list, struct wm0010_boot_xfer,
-                                       list);
-               kfree(xfer->t.rx_buf);
-               kfree(xfer->t.tx_buf);
-               list_del(&xfer->list);
-               kfree(xfer);
-       }
-
        return 0;
 
 abort: