Merge branch 'modsplit-Oct31_2011' of git://git.kernel.org/pub/scm/linux/kernel/git...
[pandora-kernel.git] / drivers / dma / imx-sdma.c
index b939e16..f993955 100644 (file)
@@ -18,6 +18,7 @@
  */
 
 #include <linux/init.h>
+#include <linux/module.h>
 #include <linux/types.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
@@ -319,6 +320,7 @@ struct sdma_engine {
        dma_addr_t                      context_phys;
        struct dma_device               dma_device;
        struct clk                      *clk;
+       struct mutex                    channel_0_lock;
        struct sdma_script_start_addrs  *script_addrs;
 };
 
@@ -416,11 +418,15 @@ static int sdma_load_script(struct sdma_engine *sdma, void *buf, int size,
        dma_addr_t buf_phys;
        int ret;
 
+       mutex_lock(&sdma->channel_0_lock);
+
        buf_virt = dma_alloc_coherent(NULL,
                        size,
                        &buf_phys, GFP_KERNEL);
-       if (!buf_virt)
-               return -ENOMEM;
+       if (!buf_virt) {
+               ret = -ENOMEM;
+               goto err_out;
+       }
 
        bd0->mode.command = C0_SETPM;
        bd0->mode.status = BD_DONE | BD_INTR | BD_WRAP | BD_EXTD;
@@ -434,6 +440,9 @@ static int sdma_load_script(struct sdma_engine *sdma, void *buf, int size,
 
        dma_free_coherent(NULL, size, buf_virt, buf_phys);
 
+err_out:
+       mutex_unlock(&sdma->channel_0_lock);
+
        return ret;
 }
 
@@ -657,6 +666,8 @@ static int sdma_load_context(struct sdma_channel *sdmac)
        dev_dbg(sdma->dev, "event_mask0 = 0x%08x\n", sdmac->event_mask0);
        dev_dbg(sdma->dev, "event_mask1 = 0x%08x\n", sdmac->event_mask1);
 
+       mutex_lock(&sdma->channel_0_lock);
+
        memset(context, 0, sizeof(*context));
        context->channel_state.pc = load_address;
 
@@ -677,6 +688,8 @@ static int sdma_load_context(struct sdma_channel *sdmac)
 
        ret = sdma_run_channel(&sdma->channel[0]);
 
+       mutex_unlock(&sdma->channel_0_lock);
+
        return ret;
 }
 
@@ -1132,18 +1145,17 @@ static void sdma_add_scripts(struct sdma_engine *sdma,
                        saddr_arr[i] = addr_arr[i];
 }
 
-static int __init sdma_get_firmware(struct sdma_engine *sdma,
-               const char *fw_name)
+static void sdma_load_firmware(const struct firmware *fw, void *context)
 {
-       const struct firmware *fw;
+       struct sdma_engine *sdma = context;
        const struct sdma_firmware_header *header;
-       int ret;
        const struct sdma_script_start_addrs *addr;
        unsigned short *ram_code;
 
-       ret = request_firmware(&fw, fw_name, sdma->dev);
-       if (ret)
-               return ret;
+       if (!fw) {
+               dev_err(sdma->dev, "firmware not found\n");
+               return;
+       }
 
        if (fw->size < sizeof(*header))
                goto err_firmware;
@@ -1173,6 +1185,16 @@ static int __init sdma_get_firmware(struct sdma_engine *sdma,
 
 err_firmware:
        release_firmware(fw);
+}
+
+static int __init sdma_get_firmware(struct sdma_engine *sdma,
+               const char *fw_name)
+{
+       int ret;
+
+       ret = request_firmware_nowait(THIS_MODULE,
+                       FW_ACTION_HOTPLUG, fw_name, sdma->dev,
+                       GFP_KERNEL, sdma, sdma_load_firmware);
 
        return ret;
 }
@@ -1270,11 +1292,14 @@ static int __init sdma_probe(struct platform_device *pdev)
        struct sdma_platform_data *pdata = pdev->dev.platform_data;
        int i;
        struct sdma_engine *sdma;
+       s32 *saddr_arr;
 
        sdma = kzalloc(sizeof(*sdma), GFP_KERNEL);
        if (!sdma)
                return -ENOMEM;
 
+       mutex_init(&sdma->channel_0_lock);
+
        sdma->dev = &pdev->dev;
 
        iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1311,6 +1336,11 @@ static int __init sdma_probe(struct platform_device *pdev)
                goto err_alloc;
        }
 
+       /* initially no scripts available */
+       saddr_arr = (s32 *)sdma->script_addrs;
+       for (i = 0; i < SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1; i++)
+               saddr_arr[i] = -EINVAL;
+
        if (of_id)
                pdev->id_entry = of_id->data;
        sdma->devtype = pdev->id_entry->driver_data;