18ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt/*
28ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt * SDIO access interface for drivers - linux specific (pci only)
38ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt *
4832523286e7a5d2fb5ea9f4b87659508d44cdf45Dmitry Shmidt * Copyright (C) 1999-2012, Broadcom Corporation
58ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt *
6832523286e7a5d2fb5ea9f4b87659508d44cdf45Dmitry Shmidt *      Unless you and Broadcom execute a separate written software license
78ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt * agreement governing use of this software, this software is licensed to you
88ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt * under the terms of the GNU General Public License version 2 (the "GPL"),
98ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt * available at http://www.broadcom.com/licenses/GPLv2.php, with the
108ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt * following added to such license:
118ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt *
128ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt *      As a special exception, the copyright holders of this software give you
138ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt * permission to link this software with independent modules, and to copy and
148ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt * distribute the resulting executable under terms of your choice, provided that
158ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt * you also meet, for each linked independent module, the terms and conditions of
168ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt * the license of that module.  An independent module is a module which is not
178ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt * derived from this software.  The special exception does not apply to any
188ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt * modifications of the software.
198ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt *
208ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt *      Notwithstanding the above, under no circumstances may you combine this
218ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt * software in any way with any other Broadcom software provided under a license
228ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt * other than the GPL, without Broadcom's express prior written consent.
238ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt *
248f237d3133b0672c337c27a1e34daad2b4e76f45Dmitry Shmidt * $Id: bcmsdh_linux.c 347638 2012-07-27 11:39:03Z $
258ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt */
268ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
278ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt/**
288ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt * @file bcmsdh_linux.c
298ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt */
308ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
318ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#define __UNDEF_NO_VERSION__
328ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
338ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#include <typedefs.h>
348ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#include <linuxver.h>
358ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
368ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#include <linux/pci.h>
378ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#include <linux/completion.h>
388ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
398ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#include <osl.h>
408ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#include <pcicfg.h>
418ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#include <bcmdefs.h>
428ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#include <bcmdevs.h>
438ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
448ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#if defined(OOB_INTR_ONLY)
458ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#include <linux/irq.h>
468ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtextern void dhdsdio_isr(void * args);
478ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#include <bcmutils.h>
488ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#include <dngl_stats.h>
498ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#include <dhd.h>
508ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#endif /* defined(OOB_INTR_ONLY) */
518ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
528f237d3133b0672c337c27a1e34daad2b4e76f45Dmitry Shmidt
538ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt/**
548ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt * SDIO Host Controller info
558ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt */
568ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidttypedef struct bcmsdh_hc bcmsdh_hc_t;
578ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
588ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtstruct bcmsdh_hc {
598ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	bcmsdh_hc_t *next;
608ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#ifdef BCMPLATFORM_BUS
618ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	struct device *dev;			/* platform device handle */
628ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#else
638ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	struct pci_dev *dev;		/* pci device handle */
648ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#endif /* BCMPLATFORM_BUS */
658ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	osl_t *osh;
668ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	void *regs;			/* SDIO Host Controller address */
678ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	bcmsdh_info_t *sdh;		/* SDIO Host Controller handle */
688ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	void *ch;
698ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	unsigned int oob_irq;
708ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	unsigned long oob_flags; /* OOB Host specifiction as edge and etc */
718ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	bool oob_irq_registered;
728ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	bool oob_irq_enable_flag;
738ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#if defined(OOB_INTR_ONLY)
748ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	spinlock_t irq_lock;
758f237d3133b0672c337c27a1e34daad2b4e76f45Dmitry Shmidt#endif /* defined(OOB_INTR_ONLY) */
768ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt};
778ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtstatic bcmsdh_hc_t *sdhcinfo = NULL;
788ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
798ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt/* driver info, initialized when bcmsdh_register is called */
808ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtstatic bcmsdh_driver_t drvinfo = {NULL, NULL};
818ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
828ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt/* debugging macros */
838ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#define SDLX_MSG(x)
848ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
858ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt/**
868ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt * Checks to see if vendor and device IDs match a supported SDIO Host Controller.
878ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt */
888ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtbool
898ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtbcmsdh_chipmatch(uint16 vendor, uint16 device)
908ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt{
918ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	/* Add other vendors and devices as required */
928ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
938ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#ifdef BCMSDIOH_STD
948ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	/* Check for Arasan host controller */
958ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	if (vendor == VENDOR_SI_IMAGE) {
968ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		return (TRUE);
978ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	}
988ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	/* Check for BRCM 27XX Standard host controller */
998ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	if (device == BCM27XX_SDIOH_ID && vendor == VENDOR_BROADCOM) {
1008ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		return (TRUE);
1018ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	}
1028ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	/* Check for BRCM Standard host controller */
1038ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	if (device == SDIOH_FPGA_ID && vendor == VENDOR_BROADCOM) {
1048ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		return (TRUE);
1058ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	}
1068ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	/* Check for TI PCIxx21 Standard host controller */
1078ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	if (device == PCIXX21_SDIOH_ID && vendor == VENDOR_TI) {
1088ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		return (TRUE);
1098ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	}
1108ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	if (device == PCIXX21_SDIOH0_ID && vendor == VENDOR_TI) {
1118ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		return (TRUE);
1128ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	}
1138ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	/* Ricoh R5C822 Standard SDIO Host */
1148ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	if (device == R5C822_SDIOH_ID && vendor == VENDOR_RICOH) {
1158ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		return (TRUE);
1168ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	}
1178ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	/* JMicron Standard SDIO Host */
1188ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	if (device == JMICRON_SDIOH_ID && vendor == VENDOR_JMICRON) {
1198ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		return (TRUE);
1208ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	}
1218ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
1228ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#endif /* BCMSDIOH_STD */
1238ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#ifdef BCMSDIOH_SPI
1248ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	/* This is the PciSpiHost. */
1258ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	if (device == SPIH_FPGA_ID && vendor == VENDOR_BROADCOM) {
1268ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		printf("Found PCI SPI Host Controller\n");
1278ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		return (TRUE);
1288ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	}
1298ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
1308ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#endif /* BCMSDIOH_SPI */
1318ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
1328ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	return (FALSE);
1338ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt}
1348ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
1358ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#if defined(BCMPLATFORM_BUS)
1368ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#if defined(BCMLXSDMMC)
1378ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt/* forward declarations */
1388ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtint bcmsdh_probe(struct device *dev);
1398ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtint bcmsdh_remove(struct device *dev);
1408ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
1418ce1727333a1c411bb88330d69f82386a118c6bfDmitry ShmidtEXPORT_SYMBOL(bcmsdh_probe);
1428ce1727333a1c411bb88330d69f82386a118c6bfDmitry ShmidtEXPORT_SYMBOL(bcmsdh_remove);
1438ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
1448ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#else
1458ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt/* forward declarations */
1468ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtstatic int __devinit bcmsdh_probe(struct device *dev);
1478ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtstatic int __devexit bcmsdh_remove(struct device *dev);
1488f237d3133b0672c337c27a1e34daad2b4e76f45Dmitry Shmidt#endif /* defined(BCMLXSDMMC) */
1498ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
1508f237d3133b0672c337c27a1e34daad2b4e76f45Dmitry Shmidt#if !defined(BCMLXSDMMC)
1518ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtstatic
1528f237d3133b0672c337c27a1e34daad2b4e76f45Dmitry Shmidt#endif /* !defined(BCMLXSDMMC) */
1538ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtint bcmsdh_probe(struct device *dev)
1548ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt{
1558ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	osl_t *osh = NULL;
1568ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	bcmsdh_hc_t *sdhc = NULL;
1578ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	ulong regs = 0;
1588ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	bcmsdh_info_t *sdh = NULL;
1598ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#if !defined(BCMLXSDMMC) && defined(BCMPLATFORM_BUS)
1608ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	struct platform_device *pdev;
1618ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	struct resource *r;
1628f237d3133b0672c337c27a1e34daad2b4e76f45Dmitry Shmidt#endif /* !defined(BCMLXSDMMC) && defined(BCMPLATFORM_BUS) */
1638ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	int irq = 0;
1648ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	uint32 vendevid;
1658ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	unsigned long irq_flags = 0;
1668ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
1678ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#if !defined(BCMLXSDMMC) && defined(BCMPLATFORM_BUS)
1688ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	pdev = to_platform_device(dev);
1698ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1708ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	irq = platform_get_irq(pdev, 0);
1718ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	if (!r || irq == NO_IRQ)
1728ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		return -ENXIO;
1738f237d3133b0672c337c27a1e34daad2b4e76f45Dmitry Shmidt#endif /* !defined(BCMLXSDMMC) && defined(BCMPLATFORM_BUS) */
1748ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
1758ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#if defined(OOB_INTR_ONLY)
1768ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#ifdef HW_OOB
1778ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	irq_flags =
1788ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | IORESOURCE_IRQ_SHAREABLE;
1798ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#else
1808ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	 irq_flags = IRQF_TRIGGER_FALLING;
1818ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#endif /* HW_OOB */
1828ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
1838ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	/* Get customer specific OOB IRQ parametres: IRQ number as IRQ type */
1848ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	irq = dhd_customer_oob_irq_map(&irq_flags);
1858ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	if  (irq < 0) {
1868ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		SDLX_MSG(("%s: Host irq is not defined\n", __FUNCTION__));
1878ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		return 1;
1888ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	}
1898ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#endif /* defined(OOB_INTR_ONLY) */
1908ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	/* allocate SDIO Host Controller state info */
1918ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	if (!(osh = osl_attach(dev, PCI_BUS, FALSE))) {
1928ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		SDLX_MSG(("%s: osl_attach failed\n", __FUNCTION__));
1938ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		goto err;
1948ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	}
1958ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	if (!(sdhc = MALLOC(osh, sizeof(bcmsdh_hc_t)))) {
1968ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		SDLX_MSG(("%s: out of memory, allocated %d bytes\n",
1978ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt			__FUNCTION__,
1988ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt			MALLOCED(osh)));
1998ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		goto err;
2008ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	}
2018ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	bzero(sdhc, sizeof(bcmsdh_hc_t));
2028ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	sdhc->osh = osh;
2038ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
2048ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	sdhc->dev = (void *)dev;
2058ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
2068f237d3133b0672c337c27a1e34daad2b4e76f45Dmitry Shmidt#if defined(BCMLXSDMMC)
2078ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	if (!(sdh = bcmsdh_attach(osh, (void *)0,
2088ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	                          (void **)&regs, irq))) {
2098ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		SDLX_MSG(("%s: bcmsdh_attach failed\n", __FUNCTION__));
2108ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		goto err;
2118ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	}
2128ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#else
2138ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	if (!(sdh = bcmsdh_attach(osh, (void *)r->start,
2148ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	                          (void **)&regs, irq))) {
2158ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		SDLX_MSG(("%s: bcmsdh_attach failed\n", __FUNCTION__));
2168ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		goto err;
2178ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	}
2188f237d3133b0672c337c27a1e34daad2b4e76f45Dmitry Shmidt#endif /* defined(BCMLXSDMMC) */
2198ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	sdhc->sdh = sdh;
2208ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	sdhc->oob_irq = irq;
2218ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	sdhc->oob_flags = irq_flags;
2228ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	sdhc->oob_irq_registered = FALSE;	/* to make sure.. */
2238ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	sdhc->oob_irq_enable_flag = FALSE;
2248ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#if defined(OOB_INTR_ONLY)
2258ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	spin_lock_init(&sdhc->irq_lock);
2268f237d3133b0672c337c27a1e34daad2b4e76f45Dmitry Shmidt#endif /* defined(BCMLXSDMMC) */
2278ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
2288ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	/* chain SDIO Host Controller info together */
2298ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	sdhc->next = sdhcinfo;
2308ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	sdhcinfo = sdhc;
2318ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
2328ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	/* Read the vendor/device ID from the CIS */
2338ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	vendevid = bcmsdh_query_device(sdh);
2348ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	/* try to attach to the target device */
2358ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	if (!(sdhc->ch = drvinfo.attach((vendevid >> 16),
2368ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	                                 (vendevid & 0xFFFF), 0, 0, 0, 0,
2378ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	                                (void *)regs, NULL, sdh))) {
2388ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		SDLX_MSG(("%s: device attach failed\n", __FUNCTION__));
2398ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		goto err;
2408ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	}
2418ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
2428ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	return 0;
2438ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
2448ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	/* error handling */
2458ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidterr:
2468ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	if (sdhc) {
2478ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		if (sdhc->sdh)
2488ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt			bcmsdh_detach(sdhc->osh, sdhc->sdh);
2498ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		MFREE(osh, sdhc, sizeof(bcmsdh_hc_t));
2508ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	}
2518ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	if (osh)
2528ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		osl_detach(osh);
2538ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	return -ENODEV;
2548ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt}
2558ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
2568f237d3133b0672c337c27a1e34daad2b4e76f45Dmitry Shmidt#if !defined(BCMLXSDMMC)
2578ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtstatic
2588f237d3133b0672c337c27a1e34daad2b4e76f45Dmitry Shmidt#endif /* !defined(BCMLXSDMMC) */
2598ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtint bcmsdh_remove(struct device *dev)
2608ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt{
2618ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	bcmsdh_hc_t *sdhc, *prev;
2628ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	osl_t *osh;
2638ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
2648ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	sdhc = sdhcinfo;
2658ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	drvinfo.detach(sdhc->ch);
2668ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	bcmsdh_detach(sdhc->osh, sdhc->sdh);
2678ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
2688ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	/* find the SDIO Host Controller state for this pdev and take it out from the list */
2698ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	for (sdhc = sdhcinfo, prev = NULL; sdhc; sdhc = sdhc->next) {
2708ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		if (sdhc->dev == (void *)dev) {
2718ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt			if (prev)
2728ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt				prev->next = sdhc->next;
2738ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt			else
2748ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt				sdhcinfo = NULL;
2758ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt			break;
2768ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		}
2778ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		prev = sdhc;
2788ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	}
2798ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	if (!sdhc) {
2808ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		SDLX_MSG(("%s: failed\n", __FUNCTION__));
2818ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		return 0;
2828ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	}
2838ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
2848ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	/* release SDIO Host Controller info */
2858ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	osh = sdhc->osh;
2868ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	MFREE(osh, sdhc, sizeof(bcmsdh_hc_t));
2878ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	osl_detach(osh);
2888ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
2898ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#if !defined(BCMLXSDMMC) || defined(OOB_INTR_ONLY)
2908ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	dev_set_drvdata(dev, NULL);
2918ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#endif /* !defined(BCMLXSDMMC) || defined(OOB_INTR_ONLY) */
2928ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
2938ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	return 0;
2948ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt}
2958ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
2968ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#else /* BCMPLATFORM_BUS */
2978ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
2988ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#if !defined(BCMLXSDMMC)
2998ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt/* forward declarations for PCI probe and remove functions. */
3008ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtstatic int __devinit bcmsdh_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
3018ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtstatic void __devexit bcmsdh_pci_remove(struct pci_dev *pdev);
3028ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
3038ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt/**
3048ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt * pci id table
3058ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt */
3068ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtstatic struct pci_device_id bcmsdh_pci_devid[] __devinitdata = {
3078ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	{ vendor: PCI_ANY_ID,
3088ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	device: PCI_ANY_ID,
3098ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	subvendor: PCI_ANY_ID,
3108ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	subdevice: PCI_ANY_ID,
3118ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	class: 0,
3128ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	class_mask: 0,
3138ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	driver_data: 0,
3148ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	},
3158ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	{ 0, }
3168ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt};
3178ce1727333a1c411bb88330d69f82386a118c6bfDmitry ShmidtMODULE_DEVICE_TABLE(pci, bcmsdh_pci_devid);
3188ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
3198ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt/**
3208ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt * SDIO Host Controller pci driver info
3218ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt */
3228ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtstatic struct pci_driver bcmsdh_pci_driver = {
3238ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	node:		{},
3248ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	name:		"bcmsdh",
3258ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	id_table:	bcmsdh_pci_devid,
3268ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	probe:		bcmsdh_pci_probe,
3278ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	remove:		bcmsdh_pci_remove,
3288ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
3298ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	save_state:	NULL,
3308ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#endif
3318ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	suspend:	NULL,
3328ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	resume:		NULL,
3338ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	};
3348ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
3358ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
3368ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtextern uint sd_pci_slot;	/* Force detection to a particular PCI */
3378ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt							/* slot only . Allows for having multiple */
3388ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt							/* WL devices at once in a PC */
3398ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt							/* Only one instance of dhd will be */
3408ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt							/* usable at a time */
3418ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt							/* Upper word is bus number, */
3428ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt							/* lower word is slot number */
3438ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt							/* Default value of 0xffffffff turns this */
3448ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt							/* off */
3458ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtmodule_param(sd_pci_slot, uint, 0);
3468ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
3478ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
3488ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt/**
3498ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt * Detect supported SDIO Host Controller and attach if found.
3508ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt *
3518ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt * Determine if the device described by pdev is a supported SDIO Host
3528ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt * Controller.  If so, attach to it and attach to the target device.
3538ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt */
3548ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtstatic int __devinit
3558ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtbcmsdh_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
3568ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt{
3578ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	osl_t *osh = NULL;
3588ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	bcmsdh_hc_t *sdhc = NULL;
3598ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	ulong regs;
3608ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	bcmsdh_info_t *sdh = NULL;
3618ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	int rc;
3628ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
3638ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	if (sd_pci_slot != 0xFFFFffff) {
3648ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		if (pdev->bus->number != (sd_pci_slot>>16) ||
3658ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt			PCI_SLOT(pdev->devfn) != (sd_pci_slot&0xffff)) {
3668ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt			SDLX_MSG(("%s: %s: bus %X, slot %X, vend %X, dev %X\n",
3678ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt				__FUNCTION__,
3688ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt				bcmsdh_chipmatch(pdev->vendor, pdev->device)
3698ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt				?"Found compatible SDIOHC"
3708ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt				:"Probing unknown device",
3718ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt				pdev->bus->number, PCI_SLOT(pdev->devfn), pdev->vendor,
3728ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt				pdev->device));
3738ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt			return -ENODEV;
3748ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		}
3758ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		SDLX_MSG(("%s: %s: bus %X, slot %X, vendor %X, device %X (good PCI location)\n",
3768ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt			__FUNCTION__,
3778ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt			bcmsdh_chipmatch(pdev->vendor, pdev->device)
3788ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt			?"Using compatible SDIOHC"
3798ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt			:"WARNING, forced use of unkown device",
3808ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt			pdev->bus->number, PCI_SLOT(pdev->devfn), pdev->vendor, pdev->device));
3818ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	}
3828ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
3838ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	if ((pdev->vendor == VENDOR_TI) && ((pdev->device == PCIXX21_FLASHMEDIA_ID) ||
3848ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	    (pdev->device == PCIXX21_FLASHMEDIA0_ID))) {
3858ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		uint32 config_reg;
3868ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
3878ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		SDLX_MSG(("%s: Disabling TI FlashMedia Controller.\n", __FUNCTION__));
3888ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		if (!(osh = osl_attach(pdev, PCI_BUS, FALSE))) {
3898ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt			SDLX_MSG(("%s: osl_attach failed\n", __FUNCTION__));
3908ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt			goto err;
3918ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		}
3928ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
3938ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		config_reg = OSL_PCI_READ_CONFIG(osh, 0x4c, 4);
3948ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
3958ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		/*
3968ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		 * Set MMC_SD_DIS bit in FlashMedia Controller.
3978ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		 * Disbling the SD/MMC Controller in the FlashMedia Controller
3988ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		 * allows the Standard SD Host Controller to take over control
3998ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		 * of the SD Slot.
4008ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		 */
4018ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		config_reg |= 0x02;
4028ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		OSL_PCI_WRITE_CONFIG(osh, 0x4c, 4, config_reg);
4038ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		osl_detach(osh);
4048ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	}
4058ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	/* match this pci device with what we support */
4068ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	/* we can't solely rely on this to believe it is our SDIO Host Controller! */
4078ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	if (!bcmsdh_chipmatch(pdev->vendor, pdev->device)) {
4088ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		return -ENODEV;
4098ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	}
4108ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
4118ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	/* this is a pci device we might support */
4128ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	SDLX_MSG(("%s: Found possible SDIO Host Controller: bus %d slot %d func %d irq %d\n",
4138ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		__FUNCTION__,
4148ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		pdev->bus->number, PCI_SLOT(pdev->devfn),
4158ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		PCI_FUNC(pdev->devfn), pdev->irq));
4168ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
4178ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	/* use bcmsdh_query_device() to get the vendor ID of the target device so
4188ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	 * it will eventually appear in the Broadcom string on the console
4198ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	 */
4208ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
4218ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	/* allocate SDIO Host Controller state info */
4228ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	if (!(osh = osl_attach(pdev, PCI_BUS, FALSE))) {
4238ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		SDLX_MSG(("%s: osl_attach failed\n", __FUNCTION__));
4248ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		goto err;
4258ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	}
4268ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	if (!(sdhc = MALLOC(osh, sizeof(bcmsdh_hc_t)))) {
4278ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		SDLX_MSG(("%s: out of memory, allocated %d bytes\n",
4288ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt			__FUNCTION__,
4298ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt			MALLOCED(osh)));
4308ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		goto err;
4318ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	}
4328ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	bzero(sdhc, sizeof(bcmsdh_hc_t));
4338ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	sdhc->osh = osh;
4348ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
4358ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	sdhc->dev = pdev;
4368ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
4378ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	/* map to address where host can access */
4388ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	pci_set_master(pdev);
4398ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	rc = pci_enable_device(pdev);
4408ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	if (rc) {
4418ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		SDLX_MSG(("%s: Cannot enable PCI device\n", __FUNCTION__));
4428ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		goto err;
4438ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	}
4448ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	if (!(sdh = bcmsdh_attach(osh, (void *)(uintptr)pci_resource_start(pdev, 0),
4458ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	                          (void **)&regs, pdev->irq))) {
4468ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		SDLX_MSG(("%s: bcmsdh_attach failed\n", __FUNCTION__));
4478ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		goto err;
4488ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	}
4498ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
4508ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	sdhc->sdh = sdh;
4518ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
4528ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	/* try to attach to the target device */
4538ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	if (!(sdhc->ch = drvinfo.attach(VENDOR_BROADCOM, /* pdev->vendor, */
4548ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	                                bcmsdh_query_device(sdh) & 0xFFFF, 0, 0, 0, 0,
4558ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	                                (void *)regs, NULL, sdh))) {
4568ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		SDLX_MSG(("%s: device attach failed\n", __FUNCTION__));
4578ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		goto err;
4588ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	}
4598ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
4608ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	/* chain SDIO Host Controller info together */
4618ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	sdhc->next = sdhcinfo;
4628ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	sdhcinfo = sdhc;
4638ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
4648ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	return 0;
4658ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
4668ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	/* error handling */
4678ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidterr:
4688ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	if (sdhc) {
4698ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		if (sdhc->sdh)
4708ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt			bcmsdh_detach(sdhc->osh, sdhc->sdh);
4718ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		MFREE(osh, sdhc, sizeof(bcmsdh_hc_t));
4728ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	}
4738ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	if (osh)
4748ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		osl_detach(osh);
4758ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	return -ENODEV;
4768ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt}
4778ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
4788ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
4798ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt/**
4808ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt * Detach from target devices and SDIO Host Controller
4818ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt */
4828ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtstatic void __devexit
4838ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtbcmsdh_pci_remove(struct pci_dev *pdev)
4848ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt{
4858ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	bcmsdh_hc_t *sdhc, *prev;
4868ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	osl_t *osh;
4878ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
4888ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	/* find the SDIO Host Controller state for this pdev and take it out from the list */
4898ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	for (sdhc = sdhcinfo, prev = NULL; sdhc; sdhc = sdhc->next) {
4908ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		if (sdhc->dev == pdev) {
4918ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt			if (prev)
4928ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt				prev->next = sdhc->next;
4938ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt			else
4948ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt				sdhcinfo = NULL;
4958ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt			break;
4968ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		}
4978ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		prev = sdhc;
4988ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	}
4998ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	if (!sdhc)
5008ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		return;
5018ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
5028ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	drvinfo.detach(sdhc->ch);
5038ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
5048ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	bcmsdh_detach(sdhc->osh, sdhc->sdh);
5058ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
5068ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	/* release SDIO Host Controller info */
5078ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	osh = sdhc->osh;
5088ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	MFREE(osh, sdhc, sizeof(bcmsdh_hc_t));
5098ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	osl_detach(osh);
5108ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt}
5118ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#endif /* BCMLXSDMMC */
5128ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#endif /* BCMPLATFORM_BUS */
5138ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
5148ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtextern int sdio_function_init(void);
5158ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
516832523286e7a5d2fb5ea9f4b87659508d44cdf45Dmitry Shmidtextern int sdio_func_reg_notify(void* semaphore);
517832523286e7a5d2fb5ea9f4b87659508d44cdf45Dmitry Shmidtextern void sdio_func_unreg_notify(void);
518832523286e7a5d2fb5ea9f4b87659508d44cdf45Dmitry Shmidt
5194a3a0faf9abf605caf9ff7b27755d867b9ac9403Dmitry Shmidt#if defined(BCMLXSDMMC)
520832523286e7a5d2fb5ea9f4b87659508d44cdf45Dmitry Shmidtint bcmsdh_reg_sdio_notify(void* semaphore)
521832523286e7a5d2fb5ea9f4b87659508d44cdf45Dmitry Shmidt{
5224a3a0faf9abf605caf9ff7b27755d867b9ac9403Dmitry Shmidt	return sdio_func_reg_notify(semaphore);
523832523286e7a5d2fb5ea9f4b87659508d44cdf45Dmitry Shmidt}
524832523286e7a5d2fb5ea9f4b87659508d44cdf45Dmitry Shmidt
525832523286e7a5d2fb5ea9f4b87659508d44cdf45Dmitry Shmidtvoid bcmsdh_unreg_sdio_notify(void)
526832523286e7a5d2fb5ea9f4b87659508d44cdf45Dmitry Shmidt{
527832523286e7a5d2fb5ea9f4b87659508d44cdf45Dmitry Shmidt	sdio_func_unreg_notify();
528832523286e7a5d2fb5ea9f4b87659508d44cdf45Dmitry Shmidt}
5294a3a0faf9abf605caf9ff7b27755d867b9ac9403Dmitry Shmidt#endif /* defined(BCMLXSDMMC) */
530832523286e7a5d2fb5ea9f4b87659508d44cdf45Dmitry Shmidt
5318ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtint
5328ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtbcmsdh_register(bcmsdh_driver_t *driver)
5338ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt{
5348ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	int error = 0;
5358ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
5368ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	drvinfo = *driver;
5378ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
5388ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#if defined(BCMPLATFORM_BUS)
5398ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	SDLX_MSG(("Linux Kernel SDIO/MMC Driver\n"));
5408ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	error = sdio_function_init();
5418ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	return error;
5428ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#endif /* defined(BCMPLATFORM_BUS) */
5438ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
5448ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#if !defined(BCMPLATFORM_BUS) && !defined(BCMLXSDMMC)
5458ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
5468ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	if (!(error = pci_module_init(&bcmsdh_pci_driver)))
5478ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		return 0;
5488ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#else
5498ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	if (!(error = pci_register_driver(&bcmsdh_pci_driver)))
5508ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		return 0;
5518ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#endif
5528ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
5538ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	SDLX_MSG(("%s: pci_module_init failed 0x%x\n", __FUNCTION__, error));
5548ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#endif /* BCMPLATFORM_BUS */
5558ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
5568ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	return error;
5578ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt}
5588ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
5598ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtextern void sdio_function_cleanup(void);
5608ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
5618ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtvoid
5628ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtbcmsdh_unregister(void)
5638ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt{
5648ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
5658ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	if (bcmsdh_pci_driver.node.next)
5668ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#endif
5678ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
5688ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#if defined(BCMLXSDMMC)
5698ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	sdio_function_cleanup();
5708ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#endif /* BCMLXSDMMC */
5718ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
5728ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#if !defined(BCMPLATFORM_BUS) && !defined(BCMLXSDMMC)
5738ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	pci_unregister_driver(&bcmsdh_pci_driver);
5748ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#endif /* BCMPLATFORM_BUS */
5758ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt}
5768ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
5778ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#if defined(OOB_INTR_ONLY)
5788ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtvoid bcmsdh_oob_intr_set(bool enable)
5798ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt{
5808ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	static bool curstate = 1;
5818ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	unsigned long flags;
5828ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
5838ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	spin_lock_irqsave(&sdhcinfo->irq_lock, flags);
5848ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	if (curstate != enable) {
5858ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		if (enable)
5868ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt			enable_irq(sdhcinfo->oob_irq);
5878ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		else
5888ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt			disable_irq_nosync(sdhcinfo->oob_irq);
5898ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		curstate = enable;
5908ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	}
5918ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	spin_unlock_irqrestore(&sdhcinfo->irq_lock, flags);
5928ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt}
5938ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
5948ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtstatic irqreturn_t wlan_oob_irq(int irq, void *dev_id)
5958ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt{
5968ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	dhd_pub_t *dhdp;
5978ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
5988ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	dhdp = (dhd_pub_t *)dev_get_drvdata(sdhcinfo->dev);
5998ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
6008ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	bcmsdh_oob_intr_set(0);
6018ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
6028ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	if (dhdp == NULL) {
6038ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		SDLX_MSG(("Out of band GPIO interrupt fired way too early\n"));
6048ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		return IRQ_HANDLED;
6058ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	}
6068ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
6078ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	dhdsdio_isr((void *)dhdp->bus);
6088ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
6098ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	return IRQ_HANDLED;
6108ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt}
6118ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
6128ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtint bcmsdh_register_oob_intr(void * dhdp)
6138ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt{
6148ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	int error = 0;
6158ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
6168ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	SDLX_MSG(("%s Enter \n", __FUNCTION__));
6178ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
6188ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	/* IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | IORESOURCE_IRQ_SHAREABLE; */
6198ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
6208ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	dev_set_drvdata(sdhcinfo->dev, dhdp);
6218ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
6228ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	if (!sdhcinfo->oob_irq_registered) {
6238ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		SDLX_MSG(("%s IRQ=%d Type=%X \n", __FUNCTION__,
6248ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt			(int)sdhcinfo->oob_irq, (int)sdhcinfo->oob_flags));
6258ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		/* Refer to customer Host IRQ docs about proper irqflags definition */
6268ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		error = request_irq(sdhcinfo->oob_irq, wlan_oob_irq, sdhcinfo->oob_flags,
6278ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt			"bcmsdh_sdmmc", NULL);
6288ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		if (error)
6298ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt			return -ENODEV;
6308ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
6318f237d3133b0672c337c27a1e34daad2b4e76f45Dmitry Shmidt		error = enable_irq_wake(sdhcinfo->oob_irq);
6328f237d3133b0672c337c27a1e34daad2b4e76f45Dmitry Shmidt		if (error)
6338f237d3133b0672c337c27a1e34daad2b4e76f45Dmitry Shmidt			SDLX_MSG(("%s enable_irq_wake error=%d \n", __FUNCTION__, error));
6348ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		sdhcinfo->oob_irq_registered = TRUE;
6358ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		sdhcinfo->oob_irq_enable_flag = TRUE;
6368ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	}
6378ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
6388ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	return 0;
6398ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt}
6408ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
6418ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtvoid bcmsdh_set_irq(int flag)
6428ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt{
6438ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	if (sdhcinfo->oob_irq_registered && sdhcinfo->oob_irq_enable_flag != flag) {
6448ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		SDLX_MSG(("%s Flag = %d", __FUNCTION__, flag));
6458ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		sdhcinfo->oob_irq_enable_flag = flag;
6468ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		if (flag) {
6478ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt			enable_irq(sdhcinfo->oob_irq);
6488ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt			enable_irq_wake(sdhcinfo->oob_irq);
6498ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		} else {
6508ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt			disable_irq_wake(sdhcinfo->oob_irq);
6518ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt			disable_irq(sdhcinfo->oob_irq);
6528ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		}
6538ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	}
6548ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt}
6558ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
6568ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtvoid bcmsdh_unregister_oob_intr(void)
6578ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt{
6588ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	SDLX_MSG(("%s: Enter\n", __FUNCTION__));
6598ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
6608ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	if (sdhcinfo->oob_irq_registered == TRUE) {
6618ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		bcmsdh_set_irq(FALSE);
6628ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		free_irq(sdhcinfo->oob_irq, NULL);
6638ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt		sdhcinfo->oob_irq_registered = FALSE;
6648ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt	}
6658ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt}
6668ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#endif /* defined(OOB_INTR_ONLY) */
6678ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
6684a3a0faf9abf605caf9ff7b27755d867b9ac9403Dmitry Shmidt#if defined(BCMLXSDMMC)
6694a3a0faf9abf605caf9ff7b27755d867b9ac9403Dmitry Shmidtvoid *bcmsdh_get_drvdata(void)
6704a3a0faf9abf605caf9ff7b27755d867b9ac9403Dmitry Shmidt{
6714a3a0faf9abf605caf9ff7b27755d867b9ac9403Dmitry Shmidt	if (!sdhcinfo)
6724a3a0faf9abf605caf9ff7b27755d867b9ac9403Dmitry Shmidt		return NULL;
6734a3a0faf9abf605caf9ff7b27755d867b9ac9403Dmitry Shmidt	return dev_get_drvdata(sdhcinfo->dev);
6744a3a0faf9abf605caf9ff7b27755d867b9ac9403Dmitry Shmidt}
6754a3a0faf9abf605caf9ff7b27755d867b9ac9403Dmitry Shmidt#endif
6764a3a0faf9abf605caf9ff7b27755d867b9ac9403Dmitry Shmidt
6778ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt/* Module parameters specific to each host-controller driver */
6788ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
6798ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtextern uint sd_msglevel;	/* Debug message level */
6808ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtmodule_param(sd_msglevel, uint, 0);
6818ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
6828ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtextern uint sd_power;	/* 0 = SD Power OFF, 1 = SD Power ON. */
6838ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtmodule_param(sd_power, uint, 0);
6848ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
6858ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtextern uint sd_clock;	/* SD Clock Control, 0 = SD Clock OFF, 1 = SD Clock ON */
6868ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtmodule_param(sd_clock, uint, 0);
6878ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
6888ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtextern uint sd_divisor;	/* Divisor (-1 means external clock) */
6898ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtmodule_param(sd_divisor, uint, 0);
6908ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
6918ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtextern uint sd_sdmode;	/* Default is SD4, 0=SPI, 1=SD1, 2=SD4 */
6928ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtmodule_param(sd_sdmode, uint, 0);
6938ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
6948ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtextern uint sd_hiok;	/* Ok to use hi-speed mode */
6958ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtmodule_param(sd_hiok, uint, 0);
6968ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
6978ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtextern uint sd_f2_blocksize;
6988ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtmodule_param(sd_f2_blocksize, int, 0);
6998ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
7008ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#ifdef BCMSDIOH_STD
7018ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtextern int sd_uhsimode;
7028ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidtmodule_param(sd_uhsimode, int, 0);
7038ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#endif
7048ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
7058f237d3133b0672c337c27a1e34daad2b4e76f45Dmitry Shmidt#ifdef BCMSDIOH_TXGLOM
7068f237d3133b0672c337c27a1e34daad2b4e76f45Dmitry Shmidtextern uint sd_txglom;
7078f237d3133b0672c337c27a1e34daad2b4e76f45Dmitry Shmidtmodule_param(sd_txglom, uint, 0);
7088f237d3133b0672c337c27a1e34daad2b4e76f45Dmitry Shmidt#endif
7098f237d3133b0672c337c27a1e34daad2b4e76f45Dmitry Shmidt
7108ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#ifdef BCMSDH_MODULE
7118ce1727333a1c411bb88330d69f82386a118c6bfDmitry ShmidtEXPORT_SYMBOL(bcmsdh_attach);
7128ce1727333a1c411bb88330d69f82386a118c6bfDmitry ShmidtEXPORT_SYMBOL(bcmsdh_detach);
7138ce1727333a1c411bb88330d69f82386a118c6bfDmitry ShmidtEXPORT_SYMBOL(bcmsdh_intr_query);
7148ce1727333a1c411bb88330d69f82386a118c6bfDmitry ShmidtEXPORT_SYMBOL(bcmsdh_intr_enable);
7158ce1727333a1c411bb88330d69f82386a118c6bfDmitry ShmidtEXPORT_SYMBOL(bcmsdh_intr_disable);
7168ce1727333a1c411bb88330d69f82386a118c6bfDmitry ShmidtEXPORT_SYMBOL(bcmsdh_intr_reg);
7178ce1727333a1c411bb88330d69f82386a118c6bfDmitry ShmidtEXPORT_SYMBOL(bcmsdh_intr_dereg);
7188ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
7198ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#if defined(DHD_DEBUG)
7208ce1727333a1c411bb88330d69f82386a118c6bfDmitry ShmidtEXPORT_SYMBOL(bcmsdh_intr_pending);
7218ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#endif
7228ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
7238ce1727333a1c411bb88330d69f82386a118c6bfDmitry ShmidtEXPORT_SYMBOL(bcmsdh_devremove_reg);
7248ce1727333a1c411bb88330d69f82386a118c6bfDmitry ShmidtEXPORT_SYMBOL(bcmsdh_cfg_read);
7258ce1727333a1c411bb88330d69f82386a118c6bfDmitry ShmidtEXPORT_SYMBOL(bcmsdh_cfg_write);
7268ce1727333a1c411bb88330d69f82386a118c6bfDmitry ShmidtEXPORT_SYMBOL(bcmsdh_cis_read);
7278ce1727333a1c411bb88330d69f82386a118c6bfDmitry ShmidtEXPORT_SYMBOL(bcmsdh_reg_read);
7288ce1727333a1c411bb88330d69f82386a118c6bfDmitry ShmidtEXPORT_SYMBOL(bcmsdh_reg_write);
7298ce1727333a1c411bb88330d69f82386a118c6bfDmitry ShmidtEXPORT_SYMBOL(bcmsdh_regfail);
7308ce1727333a1c411bb88330d69f82386a118c6bfDmitry ShmidtEXPORT_SYMBOL(bcmsdh_send_buf);
7318ce1727333a1c411bb88330d69f82386a118c6bfDmitry ShmidtEXPORT_SYMBOL(bcmsdh_recv_buf);
7328ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
7338ce1727333a1c411bb88330d69f82386a118c6bfDmitry ShmidtEXPORT_SYMBOL(bcmsdh_rwdata);
7348ce1727333a1c411bb88330d69f82386a118c6bfDmitry ShmidtEXPORT_SYMBOL(bcmsdh_abort);
7358ce1727333a1c411bb88330d69f82386a118c6bfDmitry ShmidtEXPORT_SYMBOL(bcmsdh_query_device);
7368ce1727333a1c411bb88330d69f82386a118c6bfDmitry ShmidtEXPORT_SYMBOL(bcmsdh_query_iofnum);
7378ce1727333a1c411bb88330d69f82386a118c6bfDmitry ShmidtEXPORT_SYMBOL(bcmsdh_iovar_op);
7388ce1727333a1c411bb88330d69f82386a118c6bfDmitry ShmidtEXPORT_SYMBOL(bcmsdh_register);
7398ce1727333a1c411bb88330d69f82386a118c6bfDmitry ShmidtEXPORT_SYMBOL(bcmsdh_unregister);
7408ce1727333a1c411bb88330d69f82386a118c6bfDmitry ShmidtEXPORT_SYMBOL(bcmsdh_chipmatch);
7418ce1727333a1c411bb88330d69f82386a118c6bfDmitry ShmidtEXPORT_SYMBOL(bcmsdh_reset);
7428ce1727333a1c411bb88330d69f82386a118c6bfDmitry ShmidtEXPORT_SYMBOL(bcmsdh_waitlockfree);
7438ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
7448ce1727333a1c411bb88330d69f82386a118c6bfDmitry ShmidtEXPORT_SYMBOL(bcmsdh_get_dstatus);
7458ce1727333a1c411bb88330d69f82386a118c6bfDmitry ShmidtEXPORT_SYMBOL(bcmsdh_cfg_read_word);
7468ce1727333a1c411bb88330d69f82386a118c6bfDmitry ShmidtEXPORT_SYMBOL(bcmsdh_cfg_write_word);
7478ce1727333a1c411bb88330d69f82386a118c6bfDmitry ShmidtEXPORT_SYMBOL(bcmsdh_cur_sbwad);
7488ce1727333a1c411bb88330d69f82386a118c6bfDmitry ShmidtEXPORT_SYMBOL(bcmsdh_chipinfo);
7498ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt
7508ce1727333a1c411bb88330d69f82386a118c6bfDmitry Shmidt#endif /* BCMSDH_MODULE */
751