#ifndef BRCMFMAC_BUS_H
 #define BRCMFMAC_BUS_H
 
+#include <linux/kernel.h>
+#include <linux/firmware.h>
 #include "debug.h"
 
 /* IDs of the 6 default common rings of msgbuf protocol */
        BRCMF_PROTO_MSGBUF
 };
 
+/* Firmware blobs that may be available */
+enum brcmf_blob_type {
+       BRCMF_BLOB_CLM,
+};
+
 struct brcmf_mp_device;
 
 struct brcmf_bus_dcmd {
  * @wowl_config: specify if dongle is configured for wowl when going to suspend
  * @get_ramsize: obtain size of device memory.
  * @get_memdump: obtain device memory dump in provided buffer.
- * @get_fwname: obtain firmware name.
+ * @get_blob: obtain a firmware blob.
  *
  * This structure provides an abstract interface towards the
  * bus specific driver. For control messages to common driver
        void (*wowl_config)(struct device *dev, bool enabled);
        size_t (*get_ramsize)(struct device *dev);
        int (*get_memdump)(struct device *dev, void *data, size_t len);
-       int (*get_fwname)(struct device *dev, const char *ext,
-                         unsigned char *fw_name);
+       int (*get_blob)(struct device *dev, const struct firmware **fw,
+                       enum brcmf_blob_type type);
        void (*debugfs_create)(struct device *dev);
        int (*reset)(struct device *dev);
 };
 }
 
 static inline
-int brcmf_bus_get_fwname(struct brcmf_bus *bus, const char *ext,
-                        unsigned char *fw_name)
+int brcmf_bus_get_blob(struct brcmf_bus *bus, const struct firmware **fw,
+                      enum brcmf_blob_type type)
 {
-       return bus->ops->get_fwname(bus->dev, ext, fw_name);
+       return bus->ops->get_blob(bus->dev, fw, type);
 }
 
 static inline
 
        struct brcmf_bus *bus = drvr->bus_if;
        struct brcmf_dload_data_le *chunk_buf;
        const struct firmware *clm = NULL;
-       u8 clm_name[BRCMF_FW_NAME_LEN];
        u32 chunk_len;
        u32 datalen;
        u32 cumulative_len;
 
        brcmf_dbg(TRACE, "Enter\n");
 
-       memset(clm_name, 0, sizeof(clm_name));
-       err = brcmf_bus_get_fwname(bus, ".clm_blob", clm_name);
-       if (err) {
-               bphy_err(drvr, "get CLM blob file name failed (%d)\n", err);
-               return err;
-       }
-
-       err = firmware_request_nowarn(&clm, clm_name, bus->dev);
-       if (err) {
+       err = brcmf_bus_get_blob(bus, &clm, BRCMF_BLOB_CLM);
+       if (err || !clm) {
                brcmf_info("no clm_blob available (err=%d), device may have limited channels available\n",
                           err);
                return 0;
 
 
 /* per-board firmware binaries */
 MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-pcie.*.bin");
+MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-pcie.*.clm_blob");
 
 static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = {
        BRCMF_FW_ENTRY(BRCM_CC_43602_CHIP_ID, 0xFFFFFFFF, 43602),
        struct pci_dev *pdev;
        char fw_name[BRCMF_FW_NAME_LEN];
        char nvram_name[BRCMF_FW_NAME_LEN];
+       char clm_name[BRCMF_FW_NAME_LEN];
+       const struct firmware *clm_fw;
        void __iomem *regs;
        void __iomem *tcm;
        u32 ram_base;
        return 0;
 }
 
-static
-int brcmf_pcie_get_fwname(struct device *dev, const char *ext, u8 *fw_name)
+static int brcmf_pcie_get_blob(struct device *dev, const struct firmware **fw,
+                              enum brcmf_blob_type type)
 {
        struct brcmf_bus *bus_if = dev_get_drvdata(dev);
-       struct brcmf_fw_request *fwreq;
-       struct brcmf_fw_name fwnames[] = {
-               { ext, fw_name },
-       };
+       struct brcmf_pciedev *buspub = bus_if->bus_priv.pcie;
+       struct brcmf_pciedev_info *devinfo = buspub->devinfo;
 
-       fwreq = brcmf_fw_alloc_request(bus_if->chip, bus_if->chiprev,
-                                      brcmf_pcie_fwnames,
-                                      ARRAY_SIZE(brcmf_pcie_fwnames),
-                                      fwnames, ARRAY_SIZE(fwnames));
-       if (!fwreq)
-               return -ENOMEM;
+       switch (type) {
+       case BRCMF_BLOB_CLM:
+               *fw = devinfo->clm_fw;
+               devinfo->clm_fw = NULL;
+               break;
+       default:
+               return -ENOENT;
+       }
+
+       if (!*fw)
+               return -ENOENT;
 
-       kfree(fwreq);
        return 0;
 }
 
        .wowl_config = brcmf_pcie_wowl_config,
        .get_ramsize = brcmf_pcie_get_ramsize,
        .get_memdump = brcmf_pcie_get_memdump,
-       .get_fwname = brcmf_pcie_get_fwname,
+       .get_blob = brcmf_pcie_get_blob,
        .reset = brcmf_pcie_reset,
 };
 
 
 #define BRCMF_PCIE_FW_CODE     0
 #define BRCMF_PCIE_FW_NVRAM    1
+#define BRCMF_PCIE_FW_CLM      2
 
 static void brcmf_pcie_setup(struct device *dev, int ret,
                             struct brcmf_fw_request *fwreq)
        fw = fwreq->items[BRCMF_PCIE_FW_CODE].binary;
        nvram = fwreq->items[BRCMF_PCIE_FW_NVRAM].nv_data.data;
        nvram_len = fwreq->items[BRCMF_PCIE_FW_NVRAM].nv_data.len;
+       devinfo->clm_fw = fwreq->items[BRCMF_PCIE_FW_CLM].binary;
        kfree(fwreq);
 
        ret = brcmf_chip_get_raminfo(devinfo->ci);
        struct brcmf_fw_name fwnames[] = {
                { ".bin", devinfo->fw_name },
                { ".txt", devinfo->nvram_name },
+               { ".clm_blob", devinfo->clm_name },
        };
 
        fwreq = brcmf_fw_alloc_request(devinfo->ci->chip, devinfo->ci->chiprev,
        fwreq->items[BRCMF_PCIE_FW_CODE].type = BRCMF_FW_TYPE_BINARY;
        fwreq->items[BRCMF_PCIE_FW_NVRAM].type = BRCMF_FW_TYPE_NVRAM;
        fwreq->items[BRCMF_PCIE_FW_NVRAM].flags = BRCMF_FW_REQF_OPTIONAL;
+       fwreq->items[BRCMF_PCIE_FW_CLM].type = BRCMF_FW_TYPE_BINARY;
+       fwreq->items[BRCMF_PCIE_FW_CLM].flags = BRCMF_FW_REQF_OPTIONAL;
        fwreq->board_type = devinfo->settings->board_type;
        /* NVRAM reserves PCI domain 0 for Broadcom's SDK faked bus */
        fwreq->domain_nr = pci_domain_nr(devinfo->pdev->bus) + 1;
        brcmf_pcie_release_ringbuffers(devinfo);
        brcmf_pcie_reset_device(devinfo);
        brcmf_pcie_release_resource(devinfo);
+       release_firmware(devinfo->clm_fw);
 
        if (devinfo->ci)
                brcmf_chip_detach(devinfo->ci);
 
        }
 }
 
-static
-int brcmf_sdio_get_fwname(struct device *dev, const char *ext, u8 *fw_name)
+static int brcmf_sdio_get_blob(struct device *dev, const struct firmware **fw,
+                              enum brcmf_blob_type type)
 {
        struct brcmf_bus *bus_if = dev_get_drvdata(dev);
-       struct brcmf_fw_request *fwreq;
-       struct brcmf_fw_name fwnames[] = {
-               { ext, fw_name },
-       };
+       struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
 
-       fwreq = brcmf_fw_alloc_request(bus_if->chip, bus_if->chiprev,
-                                      brcmf_sdio_fwnames,
-                                      ARRAY_SIZE(brcmf_sdio_fwnames),
-                                      fwnames, ARRAY_SIZE(fwnames));
-       if (!fwreq)
-               return -ENOMEM;
+       switch (type) {
+       case BRCMF_BLOB_CLM:
+               *fw = sdiodev->clm_fw;
+               sdiodev->clm_fw = NULL;
+               break;
+       default:
+               return -ENOENT;
+       }
+
+       if (!*fw)
+               return -ENOENT;
 
-       kfree(fwreq);
        return 0;
 }
 
        .wowl_config = brcmf_sdio_wowl_config,
        .get_ramsize = brcmf_sdio_bus_get_ramsize,
        .get_memdump = brcmf_sdio_bus_get_memdump,
-       .get_fwname = brcmf_sdio_get_fwname,
+       .get_blob = brcmf_sdio_get_blob,
        .debugfs_create = brcmf_sdio_debugfs_create,
        .reset = brcmf_sdio_bus_reset
 };
 
 #define BRCMF_SDIO_FW_CODE     0
 #define BRCMF_SDIO_FW_NVRAM    1
+#define BRCMF_SDIO_FW_CLM      2
 
 static void brcmf_sdio_firmware_callback(struct device *dev, int err,
                                         struct brcmf_fw_request *fwreq)
        code = fwreq->items[BRCMF_SDIO_FW_CODE].binary;
        nvram = fwreq->items[BRCMF_SDIO_FW_NVRAM].nv_data.data;
        nvram_len = fwreq->items[BRCMF_SDIO_FW_NVRAM].nv_data.len;
+       sdiod->clm_fw = fwreq->items[BRCMF_SDIO_FW_CLM].binary;
        kfree(fwreq);
 
        /* try to download image and nvram to the dongle */
        struct brcmf_fw_name fwnames[] = {
                { ".bin", bus->sdiodev->fw_name },
                { ".txt", bus->sdiodev->nvram_name },
+               { ".clm_blob", bus->sdiodev->clm_name },
        };
 
        fwreq = brcmf_fw_alloc_request(bus->ci->chip, bus->ci->chiprev,
 
        fwreq->items[BRCMF_SDIO_FW_CODE].type = BRCMF_FW_TYPE_BINARY;
        fwreq->items[BRCMF_SDIO_FW_NVRAM].type = BRCMF_FW_TYPE_NVRAM;
+       fwreq->items[BRCMF_SDIO_FW_CLM].type = BRCMF_FW_TYPE_BINARY;
+       fwreq->items[BRCMF_SDIO_FW_CLM].flags = BRCMF_FW_REQF_OPTIONAL;
        fwreq->board_type = bus->sdiodev->settings->board_type;
 
        return fwreq;
                if (bus->sdiodev->settings)
                        brcmf_release_module_param(bus->sdiodev->settings);
 
+               release_firmware(bus->sdiodev->clm_fw);
+               bus->sdiodev->clm_fw = NULL;
                kfree(bus->rxbuf);
                kfree(bus->hdrbuf);
                kfree(bus);
 
        struct sg_table sgtable;
        char fw_name[BRCMF_FW_NAME_LEN];
        char nvram_name[BRCMF_FW_NAME_LEN];
+       char clm_name[BRCMF_FW_NAME_LEN];
        bool wowl_enabled;
        enum brcmf_sdiod_state state;
        struct brcmf_sdiod_freezer *freezer;
+       const struct firmware *clm_fw;
 };
 
 /* sdio core registers */
 
        return NULL;
 }
 
-static
-int brcmf_usb_get_fwname(struct device *dev, const char *ext, u8 *fw_name)
+static int brcmf_usb_get_blob(struct device *dev, const struct firmware **fw,
+                             enum brcmf_blob_type type)
 {
-       struct brcmf_bus *bus = dev_get_drvdata(dev);
-       struct brcmf_fw_request *fwreq;
-       struct brcmf_fw_name fwnames[] = {
-               { ext, fw_name },
-       };
-
-       fwreq = brcmf_fw_alloc_request(bus->chip, bus->chiprev,
-                                      brcmf_usb_fwnames,
-                                      ARRAY_SIZE(brcmf_usb_fwnames),
-                                      fwnames, ARRAY_SIZE(fwnames));
-       if (!fwreq)
-               return -ENOMEM;
-
-       kfree(fwreq);
-       return 0;
+       /* No blobs for USB devices... */
+       return -ENOENT;
 }
 
 static const struct brcmf_bus_ops brcmf_usb_bus_ops = {
        .txdata = brcmf_usb_tx,
        .txctl = brcmf_usb_tx_ctlpkt,
        .rxctl = brcmf_usb_rx_ctlpkt,
-       .get_fwname = brcmf_usb_get_fwname,
+       .get_blob = brcmf_usb_get_blob,
 };
 
 #define BRCMF_USB_FW_CODE      0