xref: /OK3568_Linux_fs/external/rkwifibt/drivers/infineon/bcmsdh_linux.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * SDIO access interface for drivers - linux specific (pci only)
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Portions of this code are copyright (c) 2021 Cypress Semiconductor Corporation
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * Copyright (C) 1999-2017, Broadcom Corporation
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  *      Unless you and Broadcom execute a separate written software license
9*4882a593Smuzhiyun  * agreement governing use of this software, this software is licensed to you
10*4882a593Smuzhiyun  * under the terms of the GNU General Public License version 2 (the "GPL"),
11*4882a593Smuzhiyun  * available at http://www.broadcom.com/licenses/GPLv2.php, with the
12*4882a593Smuzhiyun  * following added to such license:
13*4882a593Smuzhiyun  *
14*4882a593Smuzhiyun  *      As a special exception, the copyright holders of this software give you
15*4882a593Smuzhiyun  * permission to link this software with independent modules, and to copy and
16*4882a593Smuzhiyun  * distribute the resulting executable under terms of your choice, provided that
17*4882a593Smuzhiyun  * you also meet, for each linked independent module, the terms and conditions of
18*4882a593Smuzhiyun  * the license of that module.  An independent module is a module which is not
19*4882a593Smuzhiyun  * derived from this software.  The special exception does not apply to any
20*4882a593Smuzhiyun  * modifications of the software.
21*4882a593Smuzhiyun  *
22*4882a593Smuzhiyun  *      Notwithstanding the above, under no circumstances may you combine this
23*4882a593Smuzhiyun  * software in any way with any other Broadcom software provided under a license
24*4882a593Smuzhiyun  * other than the GPL, without Broadcom's express prior written consent.
25*4882a593Smuzhiyun  *
26*4882a593Smuzhiyun  *
27*4882a593Smuzhiyun  * <<Broadcom-WL-IPTag/Open:>>
28*4882a593Smuzhiyun  *
29*4882a593Smuzhiyun  * $Id: bcmsdh_linux.c 689948 2017-03-14 05:21:03Z $
30*4882a593Smuzhiyun  */
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun /**
33*4882a593Smuzhiyun  * @file bcmsdh_linux.c
34*4882a593Smuzhiyun  */
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun #define __UNDEF_NO_VERSION__
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun #include <typedefs.h>
39*4882a593Smuzhiyun #include <linuxver.h>
40*4882a593Smuzhiyun #include <linux/pci.h>
41*4882a593Smuzhiyun #include <linux/completion.h>
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun #include <osl.h>
44*4882a593Smuzhiyun #include <pcicfg.h>
45*4882a593Smuzhiyun #include <bcmdefs.h>
46*4882a593Smuzhiyun #include <bcmdevs.h>
47*4882a593Smuzhiyun #include <linux/irq.h>
48*4882a593Smuzhiyun extern void dhdsdio_isr(void * args);
49*4882a593Smuzhiyun #include <bcmutils.h>
50*4882a593Smuzhiyun #include <dngl_stats.h>
51*4882a593Smuzhiyun #include <dhd.h>
52*4882a593Smuzhiyun #include <dhd_linux.h>
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun /* driver info, initialized when bcmsdh_register is called */
55*4882a593Smuzhiyun static bcmsdh_driver_t drvinfo = {NULL, NULL, NULL, NULL};
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun typedef enum {
58*4882a593Smuzhiyun 	DHD_INTR_INVALID = 0,
59*4882a593Smuzhiyun 	DHD_INTR_INBAND,
60*4882a593Smuzhiyun 	DHD_INTR_HWOOB,
61*4882a593Smuzhiyun 	DHD_INTR_SWOOB
62*4882a593Smuzhiyun } DHD_HOST_INTR_TYPE;
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun /* the BCMSDH module comprises the generic part (bcmsdh.c) and OS specific layer (e.g.
65*4882a593Smuzhiyun  * bcmsdh_linux.c). Put all OS specific variables (e.g. irq number and flags) here rather
66*4882a593Smuzhiyun  * than in the common structure bcmsdh_info. bcmsdh_info only keeps a handle (os_ctx) to this
67*4882a593Smuzhiyun  * structure.
68*4882a593Smuzhiyun  */
69*4882a593Smuzhiyun typedef struct bcmsdh_os_info {
70*4882a593Smuzhiyun 	DHD_HOST_INTR_TYPE	intr_type;
71*4882a593Smuzhiyun 	int			oob_irq_num;	/* valid when hardware or software oob in use */
72*4882a593Smuzhiyun 	unsigned long		oob_irq_flags;	/* valid when hardware or software oob in use */
73*4882a593Smuzhiyun 	bool			oob_irq_registered;
74*4882a593Smuzhiyun 	bool			oob_irq_enabled;
75*4882a593Smuzhiyun 	bool			oob_irq_wake_enabled;
76*4882a593Smuzhiyun 	spinlock_t		oob_irq_spinlock;
77*4882a593Smuzhiyun 	bcmsdh_cb_fn_t		oob_irq_handler;
78*4882a593Smuzhiyun 	void			*oob_irq_handler_context;
79*4882a593Smuzhiyun 	void			*context;	/* context returned from upper layer */
80*4882a593Smuzhiyun 	void			*sdioh;		/* handle to lower layer (sdioh) */
81*4882a593Smuzhiyun 	void			*dev;		/* handle to the underlying device */
82*4882a593Smuzhiyun 	bool			dev_wake_enabled;
83*4882a593Smuzhiyun } bcmsdh_os_info_t;
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun /* debugging macros */
86*4882a593Smuzhiyun #ifdef DHD_DEBUG
87*4882a593Smuzhiyun #define SDLX_MSG(x)     do { printf x; } while (0)
88*4882a593Smuzhiyun #else /* DHD_DEBUG */
89*4882a593Smuzhiyun #define SDLX_MSG(x)
90*4882a593Smuzhiyun #endif /* DHD_DEBUG */
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun /**
93*4882a593Smuzhiyun  * Checks to see if vendor and device IDs match a supported SDIO Host Controller.
94*4882a593Smuzhiyun  */
95*4882a593Smuzhiyun bool
bcmsdh_chipmatch(uint16 vendor,uint16 device)96*4882a593Smuzhiyun bcmsdh_chipmatch(uint16 vendor, uint16 device)
97*4882a593Smuzhiyun {
98*4882a593Smuzhiyun 	/* Add other vendors and devices as required */
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun #ifdef BCMSDIOH_STD
101*4882a593Smuzhiyun 	/* Check for Arasan host controller */
102*4882a593Smuzhiyun 	if (vendor == VENDOR_SI_IMAGE) {
103*4882a593Smuzhiyun 		return (TRUE);
104*4882a593Smuzhiyun 	}
105*4882a593Smuzhiyun 	if (device == SDIOH_FPGA_ID && vendor == VENDOR_CYPRESS) {
106*4882a593Smuzhiyun 		return (TRUE);
107*4882a593Smuzhiyun 	}
108*4882a593Smuzhiyun 	/* Check for BRCM 27XX Standard host controller */
109*4882a593Smuzhiyun 	if (device == BCM27XX_SDIOH_ID && vendor == VENDOR_BROADCOM) {
110*4882a593Smuzhiyun 		return (TRUE);
111*4882a593Smuzhiyun 	}
112*4882a593Smuzhiyun 	/* Check for BRCM Standard host controller */
113*4882a593Smuzhiyun 	if (device == SDIOH_FPGA_ID && vendor == VENDOR_BROADCOM) {
114*4882a593Smuzhiyun 		return (TRUE);
115*4882a593Smuzhiyun 	}
116*4882a593Smuzhiyun 	/* Check for TI PCIxx21 Standard host controller */
117*4882a593Smuzhiyun 	if (device == PCIXX21_SDIOH_ID && vendor == VENDOR_TI) {
118*4882a593Smuzhiyun 		return (TRUE);
119*4882a593Smuzhiyun 	}
120*4882a593Smuzhiyun 	if (device == PCIXX21_SDIOH0_ID && vendor == VENDOR_TI) {
121*4882a593Smuzhiyun 		return (TRUE);
122*4882a593Smuzhiyun 	}
123*4882a593Smuzhiyun 	/* Ricoh R5C822 Standard SDIO Host */
124*4882a593Smuzhiyun 	if (device == R5C822_SDIOH_ID && vendor == VENDOR_RICOH) {
125*4882a593Smuzhiyun 		return (TRUE);
126*4882a593Smuzhiyun 	}
127*4882a593Smuzhiyun 	/* JMicron Standard SDIO Host */
128*4882a593Smuzhiyun 	if (device == JMICRON_SDIOH_ID && vendor == VENDOR_JMICRON) {
129*4882a593Smuzhiyun 		return (TRUE);
130*4882a593Smuzhiyun 	}
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun #endif /* BCMSDIOH_STD */
133*4882a593Smuzhiyun #ifdef BCMSDIOH_SPI
134*4882a593Smuzhiyun 	/* This is the PciSpiHost. */
135*4882a593Smuzhiyun 	if (device == SPIH_FPGA_ID && vendor == VENDOR_BROADCOM) {
136*4882a593Smuzhiyun 		printf("Found PCI SPI Host Controller\n");
137*4882a593Smuzhiyun 		return (TRUE);
138*4882a593Smuzhiyun 	}
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun #endif /* BCMSDIOH_SPI */
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 	return (FALSE);
143*4882a593Smuzhiyun }
144*4882a593Smuzhiyun 
bcmsdh_probe(osl_t * osh,void * dev,void * sdioh,void * adapter_info,uint bus_type,uint bus_num,uint slot_num)145*4882a593Smuzhiyun void* bcmsdh_probe(osl_t *osh, void *dev, void *sdioh, void *adapter_info, uint bus_type,
146*4882a593Smuzhiyun 	uint bus_num, uint slot_num)
147*4882a593Smuzhiyun {
148*4882a593Smuzhiyun 	ulong regs;
149*4882a593Smuzhiyun 	bcmsdh_info_t *bcmsdh;
150*4882a593Smuzhiyun 	uint32 vendevid;
151*4882a593Smuzhiyun 	bcmsdh_os_info_t *bcmsdh_osinfo = NULL;
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun 	bcmsdh = bcmsdh_attach(osh, sdioh, &regs);
154*4882a593Smuzhiyun 	if (bcmsdh == NULL) {
155*4882a593Smuzhiyun 		SDLX_MSG(("%s: bcmsdh_attach failed\n", __FUNCTION__));
156*4882a593Smuzhiyun 		goto err;
157*4882a593Smuzhiyun 	}
158*4882a593Smuzhiyun 	bcmsdh_osinfo = MALLOC(osh, sizeof(bcmsdh_os_info_t));
159*4882a593Smuzhiyun 	if (bcmsdh_osinfo == NULL) {
160*4882a593Smuzhiyun 		SDLX_MSG(("%s: failed to allocate bcmsdh_os_info_t\n", __FUNCTION__));
161*4882a593Smuzhiyun 		goto err;
162*4882a593Smuzhiyun 	}
163*4882a593Smuzhiyun 	bzero((char *)bcmsdh_osinfo, sizeof(bcmsdh_os_info_t));
164*4882a593Smuzhiyun 	bcmsdh->os_cxt = bcmsdh_osinfo;
165*4882a593Smuzhiyun 	bcmsdh_osinfo->sdioh = sdioh;
166*4882a593Smuzhiyun 	bcmsdh_osinfo->dev = dev;
167*4882a593Smuzhiyun 	osl_set_bus_handle(osh, bcmsdh);
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun #if (!defined(CONFIG_PM_WAKELOCKS) || !defined(CONFIG_HAS_WAKELOCK)) && \
170*4882a593Smuzhiyun 	(LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
171*4882a593Smuzhiyun 	if (dev && device_init_wakeup(dev, true) == 0)
172*4882a593Smuzhiyun 		bcmsdh_osinfo->dev_wake_enabled = TRUE;
173*4882a593Smuzhiyun #endif /* CONFIG_PM_WAKELOCKS ||CONFIG_HAS_WAKELOCK &&
174*4882a593Smuzhiyun 		* (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
175*4882a593Smuzhiyun 		*/
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun #if defined(OOB_INTR_ONLY)
178*4882a593Smuzhiyun 	spin_lock_init(&bcmsdh_osinfo->oob_irq_spinlock);
179*4882a593Smuzhiyun 	/* Get customer specific OOB IRQ parametres: IRQ number as IRQ type */
180*4882a593Smuzhiyun 	bcmsdh_osinfo->oob_irq_num = wifi_platform_get_irq_number(adapter_info,
181*4882a593Smuzhiyun 		&bcmsdh_osinfo->oob_irq_flags);
182*4882a593Smuzhiyun 	if  (bcmsdh_osinfo->oob_irq_num < 0) {
183*4882a593Smuzhiyun 		SDLX_MSG(("%s: Host OOB irq is not defined\n", __FUNCTION__));
184*4882a593Smuzhiyun 		goto err;
185*4882a593Smuzhiyun 	}
186*4882a593Smuzhiyun #endif /* defined(BCMLXSDMMC) */
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 	/* Read the vendor/device ID from the CIS */
189*4882a593Smuzhiyun 	vendevid = bcmsdh_query_device(bcmsdh);
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 	/* try to attach to the target device */
192*4882a593Smuzhiyun #if defined(BCMSPI) && (defined(BCMPCISPIHOST) || defined(BCMSDIOH_SPI))
193*4882a593Smuzhiyun 	bcmsdh_osinfo->context = drvinfo.probe((vendevid >> 16), (vendevid & 0xFFFF), bus_num,
194*4882a593Smuzhiyun 		slot_num, 0, bus_type, (void *)regs, NULL, bcmsdh);
195*4882a593Smuzhiyun #else
196*4882a593Smuzhiyun 	bcmsdh_osinfo->context = drvinfo.probe((vendevid >> 16), (vendevid & 0xFFFF), bus_num,
197*4882a593Smuzhiyun 		slot_num, 0, bus_type, (void *)regs, osh, bcmsdh);
198*4882a593Smuzhiyun #endif /* BCMSPI && (BCMPCISPIHOST || BCMSDIOH_SPI) */
199*4882a593Smuzhiyun 	if (bcmsdh_osinfo->context == NULL) {
200*4882a593Smuzhiyun 		SDLX_MSG(("%s: device attach failed\n", __FUNCTION__));
201*4882a593Smuzhiyun 		goto err;
202*4882a593Smuzhiyun 	}
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun 	return bcmsdh;
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 	/* error handling */
207*4882a593Smuzhiyun err:
208*4882a593Smuzhiyun 	if (bcmsdh != NULL)
209*4882a593Smuzhiyun 		bcmsdh_detach(osh, bcmsdh);
210*4882a593Smuzhiyun 	if (bcmsdh_osinfo != NULL)
211*4882a593Smuzhiyun 		MFREE(osh, bcmsdh_osinfo, sizeof(bcmsdh_os_info_t));
212*4882a593Smuzhiyun 	return NULL;
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun 
bcmsdh_remove(bcmsdh_info_t * bcmsdh)215*4882a593Smuzhiyun int bcmsdh_remove(bcmsdh_info_t *bcmsdh)
216*4882a593Smuzhiyun {
217*4882a593Smuzhiyun 	bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun #if (!defined(CONFIG_PM_WAKELOCKS) || !defined(CONFIG_HAS_WAKELOCK)) && \
220*4882a593Smuzhiyun 	(LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
221*4882a593Smuzhiyun 	if (bcmsdh_osinfo->dev)
222*4882a593Smuzhiyun 		device_init_wakeup(bcmsdh_osinfo->dev, false);
223*4882a593Smuzhiyun 	bcmsdh_osinfo->dev_wake_enabled = FALSE;
224*4882a593Smuzhiyun #endif /* CONFIG_PM_WAKELOCKS ||CONFIG_HAS_WAKELOCK &&
225*4882a593Smuzhiyun 		* (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
226*4882a593Smuzhiyun 		*/
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun 	drvinfo.remove(bcmsdh_osinfo->context);
229*4882a593Smuzhiyun 	MFREE(bcmsdh->osh, bcmsdh->os_cxt, sizeof(bcmsdh_os_info_t));
230*4882a593Smuzhiyun 	bcmsdh_detach(bcmsdh->osh, bcmsdh);
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 	return 0;
233*4882a593Smuzhiyun }
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun #ifdef DHD_WAKE_STATUS
bcmsdh_get_total_wake(bcmsdh_info_t * bcmsdh)236*4882a593Smuzhiyun int bcmsdh_get_total_wake(bcmsdh_info_t *bcmsdh)
237*4882a593Smuzhiyun {
238*4882a593Smuzhiyun 	return bcmsdh->total_wake_count;
239*4882a593Smuzhiyun }
240*4882a593Smuzhiyun 
bcmsdh_set_get_wake(bcmsdh_info_t * bcmsdh,int flag)241*4882a593Smuzhiyun int bcmsdh_set_get_wake(bcmsdh_info_t *bcmsdh, int flag)
242*4882a593Smuzhiyun {
243*4882a593Smuzhiyun 	bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
244*4882a593Smuzhiyun 	unsigned long flags;
245*4882a593Smuzhiyun 	int ret;
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun 	spin_lock_irqsave(&bcmsdh_osinfo->oob_irq_spinlock, flags);
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun 	ret = bcmsdh->pkt_wake;
250*4882a593Smuzhiyun 	bcmsdh->total_wake_count += flag;
251*4882a593Smuzhiyun 	bcmsdh->pkt_wake = flag;
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 	spin_unlock_irqrestore(&bcmsdh_osinfo->oob_irq_spinlock, flags);
254*4882a593Smuzhiyun 	return ret;
255*4882a593Smuzhiyun }
256*4882a593Smuzhiyun #endif /* DHD_WAKE_STATUS */
257*4882a593Smuzhiyun 
bcmsdh_suspend(bcmsdh_info_t * bcmsdh)258*4882a593Smuzhiyun int bcmsdh_suspend(bcmsdh_info_t *bcmsdh)
259*4882a593Smuzhiyun {
260*4882a593Smuzhiyun 	bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun 	if (drvinfo.suspend && drvinfo.suspend(bcmsdh_osinfo->context))
263*4882a593Smuzhiyun 		return -EBUSY;
264*4882a593Smuzhiyun 	return 0;
265*4882a593Smuzhiyun }
266*4882a593Smuzhiyun 
bcmsdh_resume(bcmsdh_info_t * bcmsdh)267*4882a593Smuzhiyun int bcmsdh_resume(bcmsdh_info_t *bcmsdh)
268*4882a593Smuzhiyun {
269*4882a593Smuzhiyun 	bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun 	if (drvinfo.resume)
272*4882a593Smuzhiyun 		return drvinfo.resume(bcmsdh_osinfo->context);
273*4882a593Smuzhiyun 	return 0;
274*4882a593Smuzhiyun }
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun extern int bcmsdh_register_client_driver(void);
277*4882a593Smuzhiyun extern void bcmsdh_unregister_client_driver(void);
278*4882a593Smuzhiyun extern int sdio_func_reg_notify(void* semaphore);
279*4882a593Smuzhiyun extern void sdio_func_unreg_notify(void);
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun #if defined(BCMLXSDMMC)
bcmsdh_reg_sdio_notify(void * semaphore)282*4882a593Smuzhiyun int bcmsdh_reg_sdio_notify(void* semaphore)
283*4882a593Smuzhiyun {
284*4882a593Smuzhiyun 	return sdio_func_reg_notify(semaphore);
285*4882a593Smuzhiyun }
286*4882a593Smuzhiyun 
bcmsdh_unreg_sdio_notify(void)287*4882a593Smuzhiyun void bcmsdh_unreg_sdio_notify(void)
288*4882a593Smuzhiyun {
289*4882a593Smuzhiyun 	sdio_func_unreg_notify();
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun #endif /* defined(BCMLXSDMMC) */
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun int
bcmsdh_register(bcmsdh_driver_t * driver)294*4882a593Smuzhiyun bcmsdh_register(bcmsdh_driver_t *driver)
295*4882a593Smuzhiyun {
296*4882a593Smuzhiyun 	int error = 0;
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun 	drvinfo = *driver;
299*4882a593Smuzhiyun 	SDLX_MSG(("%s: register client driver\n", __FUNCTION__));
300*4882a593Smuzhiyun 	error = bcmsdh_register_client_driver();
301*4882a593Smuzhiyun 	if (error)
302*4882a593Smuzhiyun 		SDLX_MSG(("%s: failed %d\n", __FUNCTION__, error));
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 	return error;
305*4882a593Smuzhiyun }
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun void
bcmsdh_unregister(void)308*4882a593Smuzhiyun bcmsdh_unregister(void)
309*4882a593Smuzhiyun {
310*4882a593Smuzhiyun #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
311*4882a593Smuzhiyun 		if (bcmsdh_pci_driver.node.next == NULL)
312*4882a593Smuzhiyun 			return;
313*4882a593Smuzhiyun #endif // endif
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun 	bcmsdh_unregister_client_driver();
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun 
bcmsdh_dev_pm_stay_awake(bcmsdh_info_t * bcmsdh)318*4882a593Smuzhiyun void bcmsdh_dev_pm_stay_awake(bcmsdh_info_t *bcmsdh)
319*4882a593Smuzhiyun {
320*4882a593Smuzhiyun #if (!defined(CONFIG_PM_WAKELOCKS) || !defined(CONFIG_HAS_WAKELOCK)) && \
321*4882a593Smuzhiyun 	(LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
322*4882a593Smuzhiyun 	bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
323*4882a593Smuzhiyun 	pm_stay_awake(bcmsdh_osinfo->dev);
324*4882a593Smuzhiyun #endif /* CONFIG_PM_WAKELOCKS ||CONFIG_HAS_WAKELOCK &&
325*4882a593Smuzhiyun 		* (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
326*4882a593Smuzhiyun 		*/
327*4882a593Smuzhiyun }
328*4882a593Smuzhiyun 
bcmsdh_dev_relax(bcmsdh_info_t * bcmsdh)329*4882a593Smuzhiyun void bcmsdh_dev_relax(bcmsdh_info_t *bcmsdh)
330*4882a593Smuzhiyun {
331*4882a593Smuzhiyun #if (!defined(CONFIG_PM_WAKELOCKS) || !defined(CONFIG_HAS_WAKELOCK)) && \
332*4882a593Smuzhiyun 	(LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
333*4882a593Smuzhiyun 	bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
334*4882a593Smuzhiyun 	pm_relax(bcmsdh_osinfo->dev);
335*4882a593Smuzhiyun #endif /* CONFIG_PM_WAKELOCKS ||CONFIG_HAS_WAKELOCK &&
336*4882a593Smuzhiyun 		* (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
337*4882a593Smuzhiyun 		*/
338*4882a593Smuzhiyun }
339*4882a593Smuzhiyun 
bcmsdh_dev_pm_enabled(bcmsdh_info_t * bcmsdh)340*4882a593Smuzhiyun bool bcmsdh_dev_pm_enabled(bcmsdh_info_t *bcmsdh)
341*4882a593Smuzhiyun {
342*4882a593Smuzhiyun 	bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun 	return bcmsdh_osinfo->dev_wake_enabled;
345*4882a593Smuzhiyun }
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun #if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
bcmsdh_oob_intr_set(bcmsdh_info_t * bcmsdh,bool enable)348*4882a593Smuzhiyun void bcmsdh_oob_intr_set(bcmsdh_info_t *bcmsdh, bool enable)
349*4882a593Smuzhiyun {
350*4882a593Smuzhiyun 	unsigned long flags;
351*4882a593Smuzhiyun 	bcmsdh_os_info_t *bcmsdh_osinfo;
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 	if (!bcmsdh)
354*4882a593Smuzhiyun 		return;
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun 	bcmsdh_osinfo = bcmsdh->os_cxt;
357*4882a593Smuzhiyun 	spin_lock_irqsave(&bcmsdh_osinfo->oob_irq_spinlock, flags);
358*4882a593Smuzhiyun 	if (bcmsdh_osinfo->oob_irq_enabled != enable) {
359*4882a593Smuzhiyun 		if (enable)
360*4882a593Smuzhiyun 			enable_irq(bcmsdh_osinfo->oob_irq_num);
361*4882a593Smuzhiyun 		else
362*4882a593Smuzhiyun 			disable_irq_nosync(bcmsdh_osinfo->oob_irq_num);
363*4882a593Smuzhiyun 		bcmsdh_osinfo->oob_irq_enabled = enable;
364*4882a593Smuzhiyun 	}
365*4882a593Smuzhiyun 	spin_unlock_irqrestore(&bcmsdh_osinfo->oob_irq_spinlock, flags);
366*4882a593Smuzhiyun }
367*4882a593Smuzhiyun 
wlan_oob_irq(int irq,void * dev_id)368*4882a593Smuzhiyun static irqreturn_t wlan_oob_irq(int irq, void *dev_id)
369*4882a593Smuzhiyun {
370*4882a593Smuzhiyun 	bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)dev_id;
371*4882a593Smuzhiyun 	bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
372*4882a593Smuzhiyun 
373*4882a593Smuzhiyun #ifndef BCMSPI_ANDROID
374*4882a593Smuzhiyun 	bcmsdh_oob_intr_set(bcmsdh, FALSE);
375*4882a593Smuzhiyun #endif /* !BCMSPI_ANDROID */
376*4882a593Smuzhiyun 	bcmsdh_osinfo->oob_irq_handler(bcmsdh_osinfo->oob_irq_handler_context);
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 	return IRQ_HANDLED;
379*4882a593Smuzhiyun }
380*4882a593Smuzhiyun 
bcmsdh_oob_intr_register(bcmsdh_info_t * bcmsdh,bcmsdh_cb_fn_t oob_irq_handler,void * oob_irq_handler_context)381*4882a593Smuzhiyun int bcmsdh_oob_intr_register(bcmsdh_info_t *bcmsdh, bcmsdh_cb_fn_t oob_irq_handler,
382*4882a593Smuzhiyun 	void* oob_irq_handler_context)
383*4882a593Smuzhiyun {
384*4882a593Smuzhiyun 	int err = 0;
385*4882a593Smuzhiyun 	bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun 	SDLX_MSG(("%s: Enter\n", __FUNCTION__));
388*4882a593Smuzhiyun 	if (bcmsdh_osinfo->oob_irq_registered) {
389*4882a593Smuzhiyun 		SDLX_MSG(("%s: irq is already registered\n", __FUNCTION__));
390*4882a593Smuzhiyun 		return -EBUSY;
391*4882a593Smuzhiyun 	}
392*4882a593Smuzhiyun 	SDLX_MSG(("%s OOB irq=%d flags=%X \n", __FUNCTION__,
393*4882a593Smuzhiyun 		(int)bcmsdh_osinfo->oob_irq_num, (int)bcmsdh_osinfo->oob_irq_flags));
394*4882a593Smuzhiyun 	bcmsdh_osinfo->oob_irq_handler = oob_irq_handler;
395*4882a593Smuzhiyun 	bcmsdh_osinfo->oob_irq_handler_context = oob_irq_handler_context;
396*4882a593Smuzhiyun 	bcmsdh_osinfo->oob_irq_enabled = TRUE;
397*4882a593Smuzhiyun 	bcmsdh_osinfo->oob_irq_registered = TRUE;
398*4882a593Smuzhiyun 	err = request_irq(bcmsdh_osinfo->oob_irq_num, wlan_oob_irq,
399*4882a593Smuzhiyun 		bcmsdh_osinfo->oob_irq_flags, "bcmsdh_sdmmc", bcmsdh);
400*4882a593Smuzhiyun 	if (err) {
401*4882a593Smuzhiyun 		SDLX_MSG(("%s: request_irq failed with %d\n", __FUNCTION__, err));
402*4882a593Smuzhiyun 		bcmsdh_osinfo->oob_irq_enabled = FALSE;
403*4882a593Smuzhiyun 		bcmsdh_osinfo->oob_irq_registered = FALSE;
404*4882a593Smuzhiyun 		return err;
405*4882a593Smuzhiyun 	}
406*4882a593Smuzhiyun 
407*4882a593Smuzhiyun #if defined(CONFIG_ARCH_RHEA) || defined(CONFIG_ARCH_CAPRI)
408*4882a593Smuzhiyun 	if (device_may_wakeup(bcmsdh_osinfo->dev)) {
409*4882a593Smuzhiyun #endif /* CONFIG_ARCH_RHEA || CONFIG_ARCH_CAPRI */
410*4882a593Smuzhiyun 		err = enable_irq_wake(bcmsdh_osinfo->oob_irq_num);
411*4882a593Smuzhiyun 		if (!err)
412*4882a593Smuzhiyun 			bcmsdh_osinfo->oob_irq_wake_enabled = TRUE;
413*4882a593Smuzhiyun #if defined(CONFIG_ARCH_RHEA) || defined(CONFIG_ARCH_CAPRI)
414*4882a593Smuzhiyun 	}
415*4882a593Smuzhiyun #endif /* CONFIG_ARCH_RHEA || CONFIG_ARCH_CAPRI */
416*4882a593Smuzhiyun 	return err;
417*4882a593Smuzhiyun }
418*4882a593Smuzhiyun 
bcmsdh_oob_intr_unregister(bcmsdh_info_t * bcmsdh)419*4882a593Smuzhiyun void bcmsdh_oob_intr_unregister(bcmsdh_info_t *bcmsdh)
420*4882a593Smuzhiyun {
421*4882a593Smuzhiyun 	int err = 0;
422*4882a593Smuzhiyun 	bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun 	SDLX_MSG(("%s: Enter\n", __FUNCTION__));
425*4882a593Smuzhiyun 	if (!bcmsdh_osinfo->oob_irq_registered) {
426*4882a593Smuzhiyun 		SDLX_MSG(("%s: irq is not registered\n", __FUNCTION__));
427*4882a593Smuzhiyun 		return;
428*4882a593Smuzhiyun 	}
429*4882a593Smuzhiyun 	if (bcmsdh_osinfo->oob_irq_wake_enabled) {
430*4882a593Smuzhiyun #if defined(CONFIG_ARCH_RHEA) || defined(CONFIG_ARCH_CAPRI)
431*4882a593Smuzhiyun 		if (device_may_wakeup(bcmsdh_osinfo->dev)) {
432*4882a593Smuzhiyun #endif /* CONFIG_ARCH_RHEA || CONFIG_ARCH_CAPRI */
433*4882a593Smuzhiyun 			err = disable_irq_wake(bcmsdh_osinfo->oob_irq_num);
434*4882a593Smuzhiyun 			if (!err)
435*4882a593Smuzhiyun 				bcmsdh_osinfo->oob_irq_wake_enabled = FALSE;
436*4882a593Smuzhiyun #if defined(CONFIG_ARCH_RHEA) || defined(CONFIG_ARCH_CAPRI)
437*4882a593Smuzhiyun 		}
438*4882a593Smuzhiyun #endif /* CONFIG_ARCH_RHEA || CONFIG_ARCH_CAPRI */
439*4882a593Smuzhiyun 	}
440*4882a593Smuzhiyun 	if (bcmsdh_osinfo->oob_irq_enabled) {
441*4882a593Smuzhiyun 		disable_irq(bcmsdh_osinfo->oob_irq_num);
442*4882a593Smuzhiyun 		bcmsdh_osinfo->oob_irq_enabled = FALSE;
443*4882a593Smuzhiyun 	}
444*4882a593Smuzhiyun 	free_irq(bcmsdh_osinfo->oob_irq_num, bcmsdh);
445*4882a593Smuzhiyun 	bcmsdh_osinfo->oob_irq_registered = FALSE;
446*4882a593Smuzhiyun }
447*4882a593Smuzhiyun #endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun /* Module parameters specific to each host-controller driver */
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun extern uint sd_msglevel;	/* Debug message level */
452*4882a593Smuzhiyun #ifdef DHD_DEBUG
453*4882a593Smuzhiyun module_param(sd_msglevel, uint, 0664);
454*4882a593Smuzhiyun #else /* DHD_DEBUG */
455*4882a593Smuzhiyun module_param(sd_msglevel, uint, 0);
456*4882a593Smuzhiyun #endif /* DHD_DEBUG */
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun extern uint sd_power;	/* 0 = SD Power OFF, 1 = SD Power ON. */
459*4882a593Smuzhiyun module_param(sd_power, uint, 0);
460*4882a593Smuzhiyun 
461*4882a593Smuzhiyun extern uint sd_clock;	/* SD Clock Control, 0 = SD Clock OFF, 1 = SD Clock ON */
462*4882a593Smuzhiyun module_param(sd_clock, uint, 0);
463*4882a593Smuzhiyun 
464*4882a593Smuzhiyun extern uint sd_divisor;	/* Divisor (-1 means external clock) */
465*4882a593Smuzhiyun module_param(sd_divisor, uint, 0);
466*4882a593Smuzhiyun 
467*4882a593Smuzhiyun extern uint sd_sdmode;	/* Default is SD4, 0=SPI, 1=SD1, 2=SD4 */
468*4882a593Smuzhiyun module_param(sd_sdmode, uint, 0);
469*4882a593Smuzhiyun 
470*4882a593Smuzhiyun extern uint sd_hiok;	/* Ok to use hi-speed mode */
471*4882a593Smuzhiyun module_param(sd_hiok, uint, 0);
472*4882a593Smuzhiyun 
473*4882a593Smuzhiyun extern uint sd_f2_blocksize;
474*4882a593Smuzhiyun module_param(sd_f2_blocksize, int, 0);
475*4882a593Smuzhiyun 
476*4882a593Smuzhiyun extern uint sd_f1_blocksize;
477*4882a593Smuzhiyun module_param(sd_f1_blocksize, int, 0);
478*4882a593Smuzhiyun 
479*4882a593Smuzhiyun #ifdef BCMSDIOH_STD
480*4882a593Smuzhiyun extern int sd_uhsimode;
481*4882a593Smuzhiyun module_param(sd_uhsimode, int, 0);
482*4882a593Smuzhiyun extern uint sd_tuning_period;
483*4882a593Smuzhiyun module_param(sd_tuning_period, uint, 0);
484*4882a593Smuzhiyun extern int sd_delay_value;
485*4882a593Smuzhiyun module_param(sd_delay_value, uint, 0);
486*4882a593Smuzhiyun 
487*4882a593Smuzhiyun /* SDIO Drive Strength for UHSI mode specific to SDIO3.0 */
488*4882a593Smuzhiyun extern char dhd_sdiod_uhsi_ds_override[2];
489*4882a593Smuzhiyun module_param_string(dhd_sdiod_uhsi_ds_override, dhd_sdiod_uhsi_ds_override, 2, 0);
490*4882a593Smuzhiyun 
491*4882a593Smuzhiyun #ifdef DHD_MAP_CHIP_FIRMWARE_PATH
492*4882a593Smuzhiyun extern uint sd_chip_module;
493*4882a593Smuzhiyun module_param(sd_chip_module, int, 0);
494*4882a593Smuzhiyun #endif /* DHD_MAP_CHIP_FIRMWARE_PATH */
495*4882a593Smuzhiyun 
496*4882a593Smuzhiyun #endif // endif
497*4882a593Smuzhiyun 
498*4882a593Smuzhiyun #ifdef BCMSDH_MODULE
499*4882a593Smuzhiyun EXPORT_SYMBOL(bcmsdh_attach);
500*4882a593Smuzhiyun EXPORT_SYMBOL(bcmsdh_detach);
501*4882a593Smuzhiyun EXPORT_SYMBOL(bcmsdh_intr_query);
502*4882a593Smuzhiyun EXPORT_SYMBOL(bcmsdh_intr_enable);
503*4882a593Smuzhiyun EXPORT_SYMBOL(bcmsdh_intr_disable);
504*4882a593Smuzhiyun EXPORT_SYMBOL(bcmsdh_intr_reg);
505*4882a593Smuzhiyun EXPORT_SYMBOL(bcmsdh_intr_dereg);
506*4882a593Smuzhiyun 
507*4882a593Smuzhiyun #if defined(DHD_DEBUG)
508*4882a593Smuzhiyun EXPORT_SYMBOL(bcmsdh_intr_pending);
509*4882a593Smuzhiyun #endif // endif
510*4882a593Smuzhiyun 
511*4882a593Smuzhiyun #if defined(BT_OVER_SDIO)
512*4882a593Smuzhiyun EXPORT_SYMBOL(bcmsdh_btsdio_interface_init);
513*4882a593Smuzhiyun #endif /* defined (BT_OVER_SDIO) */
514*4882a593Smuzhiyun 
515*4882a593Smuzhiyun EXPORT_SYMBOL(bcmsdh_devremove_reg);
516*4882a593Smuzhiyun EXPORT_SYMBOL(bcmsdh_cfg_read);
517*4882a593Smuzhiyun EXPORT_SYMBOL(bcmsdh_cfg_write);
518*4882a593Smuzhiyun EXPORT_SYMBOL(bcmsdh_cis_read);
519*4882a593Smuzhiyun EXPORT_SYMBOL(bcmsdh_reg_read);
520*4882a593Smuzhiyun EXPORT_SYMBOL(bcmsdh_reg_write);
521*4882a593Smuzhiyun EXPORT_SYMBOL(bcmsdh_regfail);
522*4882a593Smuzhiyun EXPORT_SYMBOL(bcmsdh_send_buf);
523*4882a593Smuzhiyun EXPORT_SYMBOL(bcmsdh_recv_buf);
524*4882a593Smuzhiyun 
525*4882a593Smuzhiyun EXPORT_SYMBOL(bcmsdh_rwdata);
526*4882a593Smuzhiyun EXPORT_SYMBOL(bcmsdh_abort);
527*4882a593Smuzhiyun EXPORT_SYMBOL(bcmsdh_query_device);
528*4882a593Smuzhiyun EXPORT_SYMBOL(bcmsdh_query_iofnum);
529*4882a593Smuzhiyun EXPORT_SYMBOL(bcmsdh_iovar_op);
530*4882a593Smuzhiyun EXPORT_SYMBOL(bcmsdh_register);
531*4882a593Smuzhiyun EXPORT_SYMBOL(bcmsdh_unregister);
532*4882a593Smuzhiyun EXPORT_SYMBOL(bcmsdh_chipmatch);
533*4882a593Smuzhiyun EXPORT_SYMBOL(bcmsdh_reset);
534*4882a593Smuzhiyun EXPORT_SYMBOL(bcmsdh_waitlockfree);
535*4882a593Smuzhiyun 
536*4882a593Smuzhiyun EXPORT_SYMBOL(bcmsdh_get_dstatus);
537*4882a593Smuzhiyun EXPORT_SYMBOL(bcmsdh_cfg_read_word);
538*4882a593Smuzhiyun EXPORT_SYMBOL(bcmsdh_cfg_write_word);
539*4882a593Smuzhiyun EXPORT_SYMBOL(bcmsdh_cur_sbwad);
540*4882a593Smuzhiyun EXPORT_SYMBOL(bcmsdh_chipinfo);
541*4882a593Smuzhiyun 
542*4882a593Smuzhiyun #endif /* BCMSDH_MODULE */
543