aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/bcmdhd/bcmsdh_linux.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/bcmdhd/bcmsdh_linux.c')
-rw-r--r--drivers/net/wireless/bcmdhd/bcmsdh_linux.c718
1 files changed, 195 insertions, 523 deletions
diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_linux.c b/drivers/net/wireless/bcmdhd/bcmsdh_linux.c
index fe19e15..ea6285b 100644
--- a/drivers/net/wireless/bcmdhd/bcmsdh_linux.c
+++ b/drivers/net/wireless/bcmdhd/bcmsdh_linux.c
@@ -1,7 +1,7 @@
/*
* SDIO access interface for drivers - linux specific (pci only)
*
- * Copyright (C) 1999-2012, Broadcom Corporation
+ * Copyright (C) 1999-2014, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: bcmsdh_linux.c 384888 2013-02-13 13:25:17Z $
+ * $Id: bcmsdh_linux.c 455573 2014-02-14 17:49:31Z $
*/
/**
@@ -32,7 +32,6 @@
#include <typedefs.h>
#include <linuxver.h>
-
#include <linux/pci.h>
#include <linux/completion.h>
@@ -40,45 +39,43 @@
#include <pcicfg.h>
#include <bcmdefs.h>
#include <bcmdevs.h>
-
-#if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
#include <linux/irq.h>
extern void dhdsdio_isr(void * args);
#include <bcmutils.h>
#include <dngl_stats.h>
#include <dhd.h>
-#endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */
-
-/**
- * SDIO Host Controller info
- */
-typedef struct bcmsdh_hc bcmsdh_hc_t;
-
-struct bcmsdh_hc {
- bcmsdh_hc_t *next;
-#ifdef BCMPLATFORM_BUS
- struct device *dev; /* platform device handle */
-#else
- struct pci_dev *dev; /* pci device handle */
-#endif /* BCMPLATFORM_BUS */
- osl_t *osh;
- void *regs; /* SDIO Host Controller address */
- bcmsdh_info_t *sdh; /* SDIO Host Controller handle */
- void *ch;
- unsigned int oob_irq;
- unsigned long oob_flags; /* OOB Host specifiction as edge and etc */
- bool oob_irq_registered;
- bool oob_irq_enable_flag;
-#if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
- spinlock_t irq_lock;
-#endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */
-};
-static bcmsdh_hc_t *sdhcinfo = NULL;
-
-struct device *pm_dev;
+#include <dhd_linux.h>
/* driver info, initialized when bcmsdh_register is called */
-static bcmsdh_driver_t drvinfo = {NULL, NULL};
+static bcmsdh_driver_t drvinfo = {NULL, NULL, NULL, NULL};
+
+typedef enum {
+ DHD_INTR_INVALID = 0,
+ DHD_INTR_INBAND,
+ DHD_INTR_HWOOB,
+ DHD_INTR_SWOOB
+} DHD_HOST_INTR_TYPE;
+
+/* the BCMSDH module comprises the generic part (bcmsdh.c) and OS specific layer (e.g.
+ * bcmsdh_linux.c). Put all OS specific variables (e.g. irq number and flags) here rather
+ * than in the common structure bcmsdh_info. bcmsdh_info only keeps a handle (os_ctx) to this
+ * structure.
+ */
+typedef struct bcmsdh_os_info {
+ DHD_HOST_INTR_TYPE intr_type;
+ int oob_irq_num; /* valid when hardware or software oob in use */
+ unsigned long oob_irq_flags; /* valid when hardware or software oob in use */
+ bool oob_irq_registered;
+ bool oob_irq_enabled;
+ bool oob_irq_wake_enabled;
+ spinlock_t oob_irq_spinlock;
+ bcmsdh_cb_fn_t oob_irq_handler;
+ void *oob_irq_handler_context;
+ void *context; /* context returned from upper layer */
+ void *sdioh; /* handle to lower layer (sdioh) */
+ void *dev; /* handle to the underlying device */
+ bool dev_wake_enabled;
+} bcmsdh_os_info_t;
/* debugging macros */
#define SDLX_MSG(x)
@@ -133,417 +130,104 @@ bcmsdh_chipmatch(uint16 vendor, uint16 device)
return (FALSE);
}
-#if defined(BCMPLATFORM_BUS)
-#if defined(BCMLXSDMMC) || defined(BCMSPI_ANDROID)
-/* forward declarations */
-int bcmsdh_probe(struct device *dev);
-int bcmsdh_remove(struct device *dev);
-
-EXPORT_SYMBOL(bcmsdh_probe);
-EXPORT_SYMBOL(bcmsdh_remove);
-
-#else
-/* forward declarations */
-static int __devinit bcmsdh_probe(struct device *dev);
-static int __devexit bcmsdh_remove(struct device *dev);
-#endif /* defined(BCMLXSDMMC) || defined(BCMSPI_ANDROID) */
-
-#if !defined(BCMLXSDMMC) && !defined(BCMSPI_ANDROID)
-static
-#endif /* !defined(BCMLXSDMMC) && !defined(BCMSPI_ANDROID) */
-int bcmsdh_probe(struct device *dev)
+void* bcmsdh_probe(osl_t *osh, void *dev, void *sdioh, void *adapter_info, uint bus_type,
+ uint bus_num, uint slot_num)
{
- osl_t *osh = NULL;
- bcmsdh_hc_t *sdhc = NULL, *sdhc_org = sdhcinfo;
- ulong regs = 0;
- bcmsdh_info_t *sdh = NULL;
-#if !defined(BCMLXSDMMC) && defined(BCMPLATFORM_BUS) && !defined(BCMSPI_ANDROID)
- struct platform_device *pdev;
- struct resource *r;
-#endif /* !defined(BCMLXSDMMC) && defined(BCMPLATFORM_BUS) && !defined(BCMSPI_ANDROID) */
- int irq = 0;
+ ulong regs;
+ bcmsdh_info_t *bcmsdh;
uint32 vendevid;
- unsigned long irq_flags = 0;
-
-#if !defined(BCMLXSDMMC) && defined(BCMPLATFORM_BUS) && !defined(BCMSPI_ANDROID)
- pdev = to_platform_device(dev);
- r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- irq = platform_get_irq(pdev, 0);
- if (!r || irq < 0)
- return -ENXIO;
-#endif /* !defined(BCMLXSDMMC) && defined(BCMPLATFORM_BUS) && !defined(BCMSPI_ANDROID) */
-
-#if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
-#ifdef HW_OOB
- irq_flags =
- IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | IORESOURCE_IRQ_SHAREABLE;
-#else
- irq_flags = IRQF_TRIGGER_FALLING;
-#endif /* HW_OOB */
+ bcmsdh_os_info_t *bcmsdh_osinfo = NULL;
- /* Get customer specific OOB IRQ parametres: IRQ number as IRQ type */
- irq = dhd_customer_oob_irq_map(&irq_flags);
- if (irq < 0) {
- SDLX_MSG(("%s: Host irq is not defined\n", __FUNCTION__));
- goto err;
- }
-#endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */
- /* allocate SDIO Host Controller state info */
- if (!(osh = osl_attach(dev, PCI_BUS, FALSE))) {
- SDLX_MSG(("%s: osl_attach failed\n", __FUNCTION__));
+ bcmsdh = bcmsdh_attach(osh, sdioh, &regs);
+ if (bcmsdh == NULL) {
+ SDLX_MSG(("%s: bcmsdh_attach failed\n", __FUNCTION__));
goto err;
}
- if (!(sdhc = MALLOC(osh, sizeof(bcmsdh_hc_t)))) {
- SDLX_MSG(("%s: out of memory, allocated %d bytes\n",
- __FUNCTION__,
- MALLOCED(osh)));
+ bcmsdh_osinfo = MALLOC(osh, sizeof(bcmsdh_os_info_t));
+ if (bcmsdh_osinfo == NULL) {
+ SDLX_MSG(("%s: failed to allocate bcmsdh_os_info_t\n", __FUNCTION__));
goto err;
}
- bzero(sdhc, sizeof(bcmsdh_hc_t));
- sdhc->osh = osh;
+ bzero((char *)bcmsdh_osinfo, sizeof(bcmsdh_os_info_t));
+ bcmsdh->os_cxt = bcmsdh_osinfo;
+ bcmsdh_osinfo->sdioh = sdioh;
+ bcmsdh_osinfo->dev = dev;
+ osl_set_bus_handle(osh, bcmsdh);
- sdhc->dev = (void *)dev;
+#if !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
+ if (dev && device_init_wakeup(dev, true) == 0)
+ bcmsdh_osinfo->dev_wake_enabled = TRUE;
+#endif /* !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) */
-#if defined(BCMLXSDMMC) || defined(BCMSPI_ANDROID)
- if (!(sdh = bcmsdh_attach(osh, (void *)0,
- (void **)&regs, irq))) {
- SDLX_MSG(("%s: bcmsdh_attach failed\n", __FUNCTION__));
- goto err;
- }
-#else
- if (!(sdh = bcmsdh_attach(osh, (void *)r->start,
- (void **)&regs, irq))) {
- SDLX_MSG(("%s: bcmsdh_attach failed\n", __FUNCTION__));
+#if defined(OOB_INTR_ONLY)
+ spin_lock_init(&bcmsdh_osinfo->oob_irq_spinlock);
+ /* Get customer specific OOB IRQ parametres: IRQ number as IRQ type */
+ bcmsdh_osinfo->oob_irq_num = wifi_platform_get_irq_number(adapter_info,
+ &bcmsdh_osinfo->oob_irq_flags);
+ if (bcmsdh_osinfo->oob_irq_num < 0) {
+ SDLX_MSG(("%s: Host OOB irq is not defined\n", __FUNCTION__));
goto err;
}
-#endif /* defined(BCMLXSDMMC) || defined(BCMSPI_ANDROID) */
- sdhc->sdh = sdh;
- sdhc->oob_irq = irq;
- sdhc->oob_flags = irq_flags;
- sdhc->oob_irq_registered = FALSE; /* to make sure.. */
- sdhc->oob_irq_enable_flag = FALSE;
-#if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
- spin_lock_init(&sdhc->irq_lock);
-#endif /* defined(BCMLXSDMMC) || defined(BCMSPI_ANDROID) */
-
- /* chain SDIO Host Controller info together */
- sdhc->next = sdhcinfo;
- sdhcinfo = sdhc;
-
-#if !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
- if (!device_init_wakeup(dev, 1))
- pm_dev = dev;
-#endif /* !CONFIG_HAS_WAKELOCK */
+#endif /* defined(BCMLXSDMMC) */
/* Read the vendor/device ID from the CIS */
- vendevid = bcmsdh_query_device(sdh);
+ vendevid = bcmsdh_query_device(bcmsdh);
/* try to attach to the target device */
- if (!(sdhc->ch = drvinfo.attach((vendevid >> 16),
- (vendevid & 0xFFFF), 0, 0, 0, 0,
- (void *)regs, NULL, sdh))) {
+ bcmsdh_osinfo->context = drvinfo.probe((vendevid >> 16), (vendevid & 0xFFFF), bus_num,
+ slot_num, 0, bus_type, (void *)regs, osh, bcmsdh);
+ if (bcmsdh_osinfo->context == NULL) {
SDLX_MSG(("%s: device attach failed\n", __FUNCTION__));
goto err;
}
- return 0;
+ return bcmsdh;
/* error handling */
err:
- if (sdhc) {
- if (sdhc->sdh)
- bcmsdh_detach(sdhc->osh, sdhc->sdh);
- MFREE(osh, sdhc, sizeof(bcmsdh_hc_t));
- sdhcinfo = sdhc_org;
- }
- if (osh)
- osl_detach(osh);
- return -ENODEV;
+ if (bcmsdh != NULL)
+ bcmsdh_detach(osh, bcmsdh);
+ if (bcmsdh_osinfo != NULL)
+ MFREE(osh, bcmsdh_osinfo, sizeof(bcmsdh_os_info_t));
+ return NULL;
}
-#if !defined(BCMLXSDMMC) && !defined(BCMSPI_ANDROID)
-static
-#endif /* !defined(BCMLXSDMMC) && !defined(BCMSPI_ANDROID) */
-int bcmsdh_remove(struct device *dev)
+int bcmsdh_remove(bcmsdh_info_t *bcmsdh)
{
- bcmsdh_hc_t *sdhc, *prev;
- osl_t *osh;
- int sdhcinfo_null = false;
-
- /* find the SDIO Host Controller state for this pdev and take it out from the list */
- for (sdhc = sdhcinfo, prev = NULL; sdhc; sdhc = sdhc->next) {
- if (sdhc->dev == (void *)dev) {
- if (prev)
- prev->next = sdhc->next;
- else {
- if (sdhc->next != NULL) {
- SDLX_MSG(("%s: more SDHC exist, should be care about it\n",
- __FUNCTION__));
- }
- sdhcinfo_null = true;
- }
- break;
- }
- prev = sdhc;
- }
- if (!sdhc) {
- SDLX_MSG(("%s: failed\n", __FUNCTION__));
- return 0;
- }
-
- /* detach ch & sdhc if dev is valid */
- drvinfo.detach(sdhc->ch);
- bcmsdh_detach(sdhc->osh, sdhc->sdh);
+ bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
#if !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
- if (pm_dev) {
- device_init_wakeup(pm_dev, 0);
- pm_dev = NULL;
- }
-#endif /* !CONFIG_HAS_WAKELOCK */
+ if (bcmsdh_osinfo->dev)
+ device_init_wakeup(bcmsdh_osinfo->dev, false);
+ bcmsdh_osinfo->dev_wake_enabled = FALSE;
+#endif /* !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) */
- if (sdhcinfo_null == true)
- sdhcinfo = NULL;
-
- /* release SDIO Host Controller info */
- osh = sdhc->osh;
- MFREE(osh, sdhc, sizeof(bcmsdh_hc_t));
- osl_detach(osh);
-
-#if !defined(BCMLXSDMMC) || defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
- dev_set_drvdata(dev, NULL);
-#endif /* !defined(BCMLXSDMMC) || defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */
+ drvinfo.remove(bcmsdh_osinfo->context);
+ MFREE(bcmsdh->osh, bcmsdh->os_cxt, sizeof(bcmsdh_os_info_t));
+ bcmsdh_detach(bcmsdh->osh, bcmsdh);
return 0;
}
-#else /* BCMPLATFORM_BUS */
-
-#if !defined(BCMLXSDMMC)
-/* forward declarations for PCI probe and remove functions. */
-static int __devinit bcmsdh_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
-static void __devexit bcmsdh_pci_remove(struct pci_dev *pdev);
-
-/**
- * pci id table
- */
-static struct pci_device_id bcmsdh_pci_devid[] __devinitdata = {
- { vendor: PCI_ANY_ID,
- device: PCI_ANY_ID,
- subvendor: PCI_ANY_ID,
- subdevice: PCI_ANY_ID,
- class: 0,
- class_mask: 0,
- driver_data: 0,
- },
- { 0, }
-};
-MODULE_DEVICE_TABLE(pci, bcmsdh_pci_devid);
-
-/**
- * SDIO Host Controller pci driver info
- */
-static struct pci_driver bcmsdh_pci_driver = {
- node: {},
- name: "bcmsdh",
- id_table: bcmsdh_pci_devid,
- probe: bcmsdh_pci_probe,
- remove: bcmsdh_pci_remove,
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
- save_state: NULL,
-#endif
- suspend: NULL,
- resume: NULL,
- };
-
-
-extern uint sd_pci_slot; /* Force detection to a particular PCI */
- /* slot only . Allows for having multiple */
- /* WL devices at once in a PC */
- /* Only one instance of dhd will be */
- /* usable at a time */
- /* Upper word is bus number, */
- /* lower word is slot number */
- /* Default value of 0xffffffff turns this */
- /* off */
-module_param(sd_pci_slot, uint, 0);
-
-
-/**
- * Detect supported SDIO Host Controller and attach if found.
- *
- * Determine if the device described by pdev is a supported SDIO Host
- * Controller. If so, attach to it and attach to the target device.
- */
-static int __devinit
-bcmsdh_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+int bcmsdh_suspend(bcmsdh_info_t *bcmsdh)
{
- osl_t *osh = NULL;
- bcmsdh_hc_t *sdhc = NULL;
- ulong regs;
- bcmsdh_info_t *sdh = NULL;
- int rc;
-
- if (sd_pci_slot != 0xFFFFffff) {
- if (pdev->bus->number != (sd_pci_slot>>16) ||
- PCI_SLOT(pdev->devfn) != (sd_pci_slot&0xffff)) {
- SDLX_MSG(("%s: %s: bus %X, slot %X, vend %X, dev %X\n",
- __FUNCTION__,
- bcmsdh_chipmatch(pdev->vendor, pdev->device)
- ?"Found compatible SDIOHC"
- :"Probing unknown device",
- pdev->bus->number, PCI_SLOT(pdev->devfn), pdev->vendor,
- pdev->device));
- return -ENODEV;
- }
- SDLX_MSG(("%s: %s: bus %X, slot %X, vendor %X, device %X (good PCI location)\n",
- __FUNCTION__,
- bcmsdh_chipmatch(pdev->vendor, pdev->device)
- ?"Using compatible SDIOHC"
- :"WARNING, forced use of unkown device",
- pdev->bus->number, PCI_SLOT(pdev->devfn), pdev->vendor, pdev->device));
- }
-
- if ((pdev->vendor == VENDOR_TI) && ((pdev->device == PCIXX21_FLASHMEDIA_ID) ||
- (pdev->device == PCIXX21_FLASHMEDIA0_ID))) {
- uint32 config_reg;
-
- SDLX_MSG(("%s: Disabling TI FlashMedia Controller.\n", __FUNCTION__));
- if (!(osh = osl_attach(pdev, PCI_BUS, FALSE))) {
- SDLX_MSG(("%s: osl_attach failed\n", __FUNCTION__));
- goto err;
- }
-
- config_reg = OSL_PCI_READ_CONFIG(osh, 0x4c, 4);
-
- /*
- * Set MMC_SD_DIS bit in FlashMedia Controller.
- * Disbling the SD/MMC Controller in the FlashMedia Controller
- * allows the Standard SD Host Controller to take over control
- * of the SD Slot.
- */
- config_reg |= 0x02;
- OSL_PCI_WRITE_CONFIG(osh, 0x4c, 4, config_reg);
- osl_detach(osh);
- }
- /* match this pci device with what we support */
- /* we can't solely rely on this to believe it is our SDIO Host Controller! */
- if (!bcmsdh_chipmatch(pdev->vendor, pdev->device)) {
- if (pdev->vendor == VENDOR_BROADCOM) {
- SDLX_MSG(("%s: Unknown Broadcom device (vendor: %#x, device: %#x).\n",
- __FUNCTION__, pdev->vendor, pdev->device));
- }
- return -ENODEV;
- }
-
- /* this is a pci device we might support */
- SDLX_MSG(("%s: Found possible SDIO Host Controller: bus %d slot %d func %d irq %d\n",
- __FUNCTION__,
- pdev->bus->number, PCI_SLOT(pdev->devfn),
- PCI_FUNC(pdev->devfn), pdev->irq));
-
- /* use bcmsdh_query_device() to get the vendor ID of the target device so
- * it will eventually appear in the Broadcom string on the console
- */
-
- /* allocate SDIO Host Controller state info */
- if (!(osh = osl_attach(pdev, PCI_BUS, FALSE))) {
- SDLX_MSG(("%s: osl_attach failed\n", __FUNCTION__));
- goto err;
- }
- if (!(sdhc = MALLOC(osh, sizeof(bcmsdh_hc_t)))) {
- SDLX_MSG(("%s: out of memory, allocated %d bytes\n",
- __FUNCTION__,
- MALLOCED(osh)));
- goto err;
- }
- bzero(sdhc, sizeof(bcmsdh_hc_t));
- sdhc->osh = osh;
-
- sdhc->dev = pdev;
-
- /* map to address where host can access */
- pci_set_master(pdev);
- rc = pci_enable_device(pdev);
- if (rc) {
- SDLX_MSG(("%s: Cannot enable PCI device\n", __FUNCTION__));
- goto err;
- }
- if (!(sdh = bcmsdh_attach(osh, (void *)(uintptr)pci_resource_start(pdev, 0),
- (void **)&regs, pdev->irq))) {
- SDLX_MSG(("%s: bcmsdh_attach failed\n", __FUNCTION__));
- goto err;
- }
-
- sdhc->sdh = sdh;
-
- /* try to attach to the target device */
- if (!(sdhc->ch = drvinfo.attach(VENDOR_BROADCOM, /* pdev->vendor, */
- bcmsdh_query_device(sdh) & 0xFFFF, 0, 0, 0, 0,
- (void *)regs, NULL, sdh))) {
- SDLX_MSG(("%s: device attach failed\n", __FUNCTION__));
- goto err;
- }
-
- /* chain SDIO Host Controller info together */
- sdhc->next = sdhcinfo;
- sdhcinfo = sdhc;
+ bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
+ if (drvinfo.suspend && drvinfo.suspend(bcmsdh_osinfo->context))
+ return -EBUSY;
return 0;
-
- /* error handling */
-err:
- if (sdhc) {
- if (sdhc->sdh)
- bcmsdh_detach(sdhc->osh, sdhc->sdh);
- MFREE(osh, sdhc, sizeof(bcmsdh_hc_t));
- }
- if (osh)
- osl_detach(osh);
- return -ENODEV;
}
-
-/**
- * Detach from target devices and SDIO Host Controller
- */
-static void __devexit
-bcmsdh_pci_remove(struct pci_dev *pdev)
+int bcmsdh_resume(bcmsdh_info_t *bcmsdh)
{
- bcmsdh_hc_t *sdhc, *prev;
- osl_t *osh;
-
- /* find the SDIO Host Controller state for this pdev and take it out from the list */
- for (sdhc = sdhcinfo, prev = NULL; sdhc; sdhc = sdhc->next) {
- if (sdhc->dev == pdev) {
- if (prev)
- prev->next = sdhc->next;
- else
- sdhcinfo = NULL;
- break;
- }
- prev = sdhc;
- }
- if (!sdhc)
- return;
-
- drvinfo.detach(sdhc->ch);
-
- bcmsdh_detach(sdhc->osh, sdhc->sdh);
+ bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
- /* release SDIO Host Controller info */
- osh = sdhc->osh;
- MFREE(osh, sdhc, sizeof(bcmsdh_hc_t));
- osl_detach(osh);
+ if (drvinfo.resume)
+ return drvinfo.resume(bcmsdh_osinfo->context);
+ return 0;
}
-#endif /* BCMLXSDMMC */
-#endif /* BCMPLATFORM_BUS */
-
-#ifdef BCMSPI_ANDROID
-extern int spi_function_init(void);
-#else
-extern int sdio_function_init(void);
-#endif /* BCMSPI_ANDROID */
+extern int bcmsdh_register_client_driver(void);
+extern void bcmsdh_unregister_client_driver(void);
extern int sdio_func_reg_notify(void* semaphore);
extern void sdio_func_unreg_notify(void);
@@ -565,160 +249,148 @@ bcmsdh_register(bcmsdh_driver_t *driver)
int error = 0;
drvinfo = *driver;
+ SDLX_MSG(("%s: register client driver\n", __FUNCTION__));
+ error = bcmsdh_register_client_driver();
+ if (error)
+ SDLX_MSG(("%s: failed %d\n", __FUNCTION__, error));
-#if defined(BCMPLATFORM_BUS)
-#ifdef BCMSPI_ANDROID
- SDLX_MSG(("Linux Kernel SPI Driver\n"));
- error = spi_function_init();
-#else /* BCMSPI_ANDROID */
- SDLX_MSG(("Linux Kernel SDIO/MMC Driver\n"));
- error = sdio_function_init();
-#endif /* BCMSPI_ANDROID */
return error;
-#endif /* defined(BCMPLATFORM_BUS) */
+}
-#if !defined(BCMPLATFORM_BUS) && !defined(BCMLXSDMMC)
+void
+bcmsdh_unregister(void)
+{
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
- if (!(error = pci_module_init(&bcmsdh_pci_driver)))
- return 0;
-#else
- if (!(error = pci_register_driver(&bcmsdh_pci_driver)))
- return 0;
+ if (bcmsdh_pci_driver.node.next == NULL)
+ return;
#endif
- SDLX_MSG(("%s: pci_module_init failed 0x%x\n", __FUNCTION__, error));
-#endif /* BCMPLATFORM_BUS */
-
- return error;
+ bcmsdh_unregister_client_driver();
}
-#ifdef BCMSPI_ANDROID
-extern void spi_function_cleanup(void);
-#else
-extern void sdio_function_cleanup(void);
-#endif /* BCMSPI_ANDROID */
+void bcmsdh_dev_pm_stay_awake(bcmsdh_info_t *bcmsdh)
+{
+#if !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
+ bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
+ pm_stay_awake(bcmsdh_osinfo->dev);
+#endif /* !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) */
+}
-void
-bcmsdh_unregister(void)
+void bcmsdh_dev_relax(bcmsdh_info_t *bcmsdh)
{
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
- if (bcmsdh_pci_driver.node.next)
-#endif
+#if !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
+ bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
+ pm_relax(bcmsdh_osinfo->dev);
+#endif /* !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) */
+}
-#ifdef BCMSPI_ANDROID
- spi_function_cleanup();
-#endif /* BCMSPI_ANDROID */
-#if defined(BCMLXSDMMC)
- sdio_function_cleanup();
-#endif /* BCMLXSDMMC */
+bool bcmsdh_dev_pm_enabled(bcmsdh_info_t *bcmsdh)
+{
+ bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
-#if !defined(BCMPLATFORM_BUS) && !defined(BCMLXSDMMC)
- pci_unregister_driver(&bcmsdh_pci_driver);
-#endif /* BCMPLATFORM_BUS */
+ return bcmsdh_osinfo->dev_wake_enabled;
}
#if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
-void bcmsdh_oob_intr_set(bool enable)
+void bcmsdh_oob_intr_set(bcmsdh_info_t *bcmsdh, bool enable)
{
- static bool curstate = 1;
unsigned long flags;
+ bcmsdh_os_info_t *bcmsdh_osinfo;
+
+ if (!bcmsdh)
+ return;
- spin_lock_irqsave(&sdhcinfo->irq_lock, flags);
- if (curstate != enable) {
+ bcmsdh_osinfo = bcmsdh->os_cxt;
+ spin_lock_irqsave(&bcmsdh_osinfo->oob_irq_spinlock, flags);
+ if (bcmsdh_osinfo->oob_irq_enabled != enable) {
if (enable)
- enable_irq(sdhcinfo->oob_irq);
+ enable_irq(bcmsdh_osinfo->oob_irq_num);
else
- disable_irq_nosync(sdhcinfo->oob_irq);
- curstate = enable;
+ disable_irq_nosync(bcmsdh_osinfo->oob_irq_num);
+ bcmsdh_osinfo->oob_irq_enabled = enable;
}
- spin_unlock_irqrestore(&sdhcinfo->irq_lock, flags);
+ spin_unlock_irqrestore(&bcmsdh_osinfo->oob_irq_spinlock, flags);
}
static irqreturn_t wlan_oob_irq(int irq, void *dev_id)
{
- dhd_pub_t *dhdp;
+ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)dev_id;
+ bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
- dhdp = (dhd_pub_t *)dev_get_drvdata(sdhcinfo->dev);
-
- bcmsdh_oob_intr_set(0);
-
- if (dhdp == NULL) {
- SDLX_MSG(("Out of band GPIO interrupt fired way too early\n"));
- return IRQ_HANDLED;
- }
-
- dhdsdio_isr((void *)dhdp->bus);
+#ifndef BCMSPI_ANDROID
+ bcmsdh_oob_intr_set(bcmsdh, FALSE);
+#endif /* !BCMSPI_ANDROID */
+ bcmsdh_osinfo->oob_irq_handler(bcmsdh_osinfo->oob_irq_handler_context);
return IRQ_HANDLED;
}
-int bcmsdh_register_oob_intr(void * dhdp)
+int bcmsdh_oob_intr_register(bcmsdh_info_t *bcmsdh, bcmsdh_cb_fn_t oob_irq_handler,
+ void* oob_irq_handler_context)
{
- int error = 0;
-
- SDLX_MSG(("%s Enter \n", __FUNCTION__));
-
- /* IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | IORESOURCE_IRQ_SHAREABLE; */
-
- dev_set_drvdata(sdhcinfo->dev, dhdp);
-
- if (!sdhcinfo->oob_irq_registered) {
- SDLX_MSG(("%s IRQ=%d Type=%X \n", __FUNCTION__,
- (int)sdhcinfo->oob_irq, (int)sdhcinfo->oob_flags));
- /* Refer to customer Host IRQ docs about proper irqflags definition */
- error = request_irq(sdhcinfo->oob_irq, wlan_oob_irq, sdhcinfo->oob_flags,
- "bcmsdh_sdmmc", NULL);
- if (error)
- return -ENODEV;
-
- error = enable_irq_wake(sdhcinfo->oob_irq);
- if (error)
- SDLX_MSG(("%s enable_irq_wake error=%d \n", __FUNCTION__, error));
- sdhcinfo->oob_irq_registered = TRUE;
- sdhcinfo->oob_irq_enable_flag = TRUE;
- }
+ int err = 0;
+ bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
- return 0;
+ SDLX_MSG(("%s: Enter\n", __FUNCTION__));
+ if (bcmsdh_osinfo->oob_irq_registered) {
+ SDLX_MSG(("%s: irq is already registered\n", __FUNCTION__));
+ return -EBUSY;
+ }
+ SDLX_MSG(("%s OOB irq=%d flags=%X \n", __FUNCTION__,
+ (int)bcmsdh_osinfo->oob_irq_num, (int)bcmsdh_osinfo->oob_irq_flags));
+ bcmsdh_osinfo->oob_irq_handler = oob_irq_handler;
+ bcmsdh_osinfo->oob_irq_handler_context = oob_irq_handler_context;
+ err = request_irq(bcmsdh_osinfo->oob_irq_num, wlan_oob_irq,
+ bcmsdh_osinfo->oob_irq_flags, "bcmsdh_sdmmc", bcmsdh);
+ if (err) {
+ SDLX_MSG(("%s: request_irq failed with %d\n", __FUNCTION__, err));
+ return err;
+ }
+
+#if defined(CONFIG_ARCH_RHEA) || defined(CONFIG_ARCH_CAPRI)
+ if (device_may_wakeup(bcmsdh_osinfo->dev)) {
+#endif /* CONFIG_ARCH_RHEA || CONFIG_ARCH_CAPRI */
+ err = enable_irq_wake(bcmsdh_osinfo->oob_irq_num);
+ if (!err)
+ bcmsdh_osinfo->oob_irq_wake_enabled = TRUE;
+#if defined(CONFIG_ARCH_RHEA) || defined(CONFIG_ARCH_CAPRI)
+ }
+#endif /* CONFIG_ARCH_RHEA || CONFIG_ARCH_CAPRI */
+ bcmsdh_osinfo->oob_irq_enabled = TRUE;
+ bcmsdh_osinfo->oob_irq_registered = TRUE;
+ return err;
}
-void bcmsdh_set_irq(int flag)
+void bcmsdh_oob_intr_unregister(bcmsdh_info_t *bcmsdh)
{
- if (sdhcinfo->oob_irq_registered && sdhcinfo->oob_irq_enable_flag != flag) {
- SDLX_MSG(("%s Flag = %d", __FUNCTION__, flag));
- sdhcinfo->oob_irq_enable_flag = flag;
- if (flag) {
- enable_irq(sdhcinfo->oob_irq);
- enable_irq_wake(sdhcinfo->oob_irq);
- } else {
-#if !(defined(BCMSPI_ANDROID) && defined(CUSTOMER_HW4) && defined(CONFIG_NKERNEL))
- disable_irq_wake(sdhcinfo->oob_irq);
-#endif /* !defined(BCMSPI_ANDROID) */
- disable_irq(sdhcinfo->oob_irq);
- }
- }
-}
+ int err = 0;
+ bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
-void bcmsdh_unregister_oob_intr(void)
-{
SDLX_MSG(("%s: Enter\n", __FUNCTION__));
-
- if (sdhcinfo->oob_irq_registered == TRUE) {
- bcmsdh_set_irq(FALSE);
- free_irq(sdhcinfo->oob_irq, NULL);
- sdhcinfo->oob_irq_registered = FALSE;
+ if (!bcmsdh_osinfo->oob_irq_registered) {
+ SDLX_MSG(("%s: irq is not registered\n", __FUNCTION__));
+ return;
+ }
+ if (bcmsdh_osinfo->oob_irq_wake_enabled) {
+#if defined(CONFIG_ARCH_RHEA) || defined(CONFIG_ARCH_CAPRI)
+ if (device_may_wakeup(bcmsdh_osinfo->dev)) {
+#endif /* CONFIG_ARCH_RHEA || CONFIG_ARCH_CAPRI */
+ err = disable_irq_wake(bcmsdh_osinfo->oob_irq_num);
+ if (!err)
+ bcmsdh_osinfo->oob_irq_wake_enabled = FALSE;
+#if defined(CONFIG_ARCH_RHEA) || defined(CONFIG_ARCH_CAPRI)
+ }
+#endif /* CONFIG_ARCH_RHEA || CONFIG_ARCH_CAPRI */
+ }
+ if (bcmsdh_osinfo->oob_irq_enabled) {
+ disable_irq(bcmsdh_osinfo->oob_irq_num);
+ bcmsdh_osinfo->oob_irq_enabled = FALSE;
}
+ free_irq(bcmsdh_osinfo->oob_irq_num, bcmsdh);
+ bcmsdh_osinfo->oob_irq_registered = FALSE;
}
#endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */
-#if defined(BCMLXSDMMC)
-void *bcmsdh_get_drvdata(void)
-{
- if (!sdhcinfo)
- return NULL;
- return dev_get_drvdata(sdhcinfo->dev);
-}
-#endif
-
/* Module parameters specific to each host-controller driver */
extern uint sd_msglevel; /* Debug message level */
@@ -749,11 +421,11 @@ extern uint sd_tuning_period;
module_param(sd_tuning_period, uint, 0);
extern int sd_delay_value;
module_param(sd_delay_value, uint, 0);
-#endif
-#ifdef BCMSDIOH_TXGLOM
-extern uint sd_txglom;
-module_param(sd_txglom, uint, 0);
+/* SDIO Drive Strength for UHSI mode specific to SDIO3.0 */
+extern char dhd_sdiod_uhsi_ds_override[2];
+module_param_string(dhd_sdiod_uhsi_ds_override, dhd_sdiod_uhsi_ds_override, 2, 0);
+
#endif
#ifdef BCMSDH_MODULE