xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/st/cw1200/cw1200_sdio.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Mac80211 SDIO driver for ST-Ericsson CW1200 device
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (c) 2010, ST-Ericsson
6*4882a593Smuzhiyun  * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include <linux/module.h>
10*4882a593Smuzhiyun #include <linux/interrupt.h>
11*4882a593Smuzhiyun #include <linux/gpio.h>
12*4882a593Smuzhiyun #include <linux/delay.h>
13*4882a593Smuzhiyun #include <linux/mmc/host.h>
14*4882a593Smuzhiyun #include <linux/mmc/sdio_func.h>
15*4882a593Smuzhiyun #include <linux/mmc/card.h>
16*4882a593Smuzhiyun #include <linux/mmc/sdio.h>
17*4882a593Smuzhiyun #include <linux/mmc/sdio_ids.h>
18*4882a593Smuzhiyun #include <net/mac80211.h>
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #include "cw1200.h"
21*4882a593Smuzhiyun #include "hwbus.h"
22*4882a593Smuzhiyun #include <linux/platform_data/net-cw1200.h>
23*4882a593Smuzhiyun #include "hwio.h"
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun MODULE_AUTHOR("Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>");
26*4882a593Smuzhiyun MODULE_DESCRIPTION("mac80211 ST-Ericsson CW1200 SDIO driver");
27*4882a593Smuzhiyun MODULE_LICENSE("GPL");
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun #define SDIO_BLOCK_SIZE (512)
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun /* Default platform data for Sagrad modules */
32*4882a593Smuzhiyun static struct cw1200_platform_data_sdio sagrad_109x_evk_platform_data = {
33*4882a593Smuzhiyun 	.ref_clk = 38400,
34*4882a593Smuzhiyun 	.have_5ghz = false,
35*4882a593Smuzhiyun 	.sdd_file = "sdd_sagrad_1091_1098.bin",
36*4882a593Smuzhiyun };
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun /* Allow platform data to be overridden */
39*4882a593Smuzhiyun static struct cw1200_platform_data_sdio *global_plat_data = &sagrad_109x_evk_platform_data;
40*4882a593Smuzhiyun 
cw1200_sdio_set_platform_data(struct cw1200_platform_data_sdio * pdata)41*4882a593Smuzhiyun void __init cw1200_sdio_set_platform_data(struct cw1200_platform_data_sdio *pdata)
42*4882a593Smuzhiyun {
43*4882a593Smuzhiyun 	global_plat_data = pdata;
44*4882a593Smuzhiyun }
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun struct hwbus_priv {
47*4882a593Smuzhiyun 	struct sdio_func	*func;
48*4882a593Smuzhiyun 	struct cw1200_common	*core;
49*4882a593Smuzhiyun 	const struct cw1200_platform_data_sdio *pdata;
50*4882a593Smuzhiyun };
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun static const struct sdio_device_id cw1200_sdio_ids[] = {
53*4882a593Smuzhiyun 	{ SDIO_DEVICE(SDIO_VENDOR_ID_STE, SDIO_DEVICE_ID_STE_CW1200) },
54*4882a593Smuzhiyun 	{ /* end: all zeroes */			},
55*4882a593Smuzhiyun };
56*4882a593Smuzhiyun MODULE_DEVICE_TABLE(sdio, cw1200_sdio_ids);
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun /* hwbus_ops implemetation */
59*4882a593Smuzhiyun 
cw1200_sdio_memcpy_fromio(struct hwbus_priv * self,unsigned int addr,void * dst,int count)60*4882a593Smuzhiyun static int cw1200_sdio_memcpy_fromio(struct hwbus_priv *self,
61*4882a593Smuzhiyun 				     unsigned int addr,
62*4882a593Smuzhiyun 				     void *dst, int count)
63*4882a593Smuzhiyun {
64*4882a593Smuzhiyun 	return sdio_memcpy_fromio(self->func, dst, addr, count);
65*4882a593Smuzhiyun }
66*4882a593Smuzhiyun 
cw1200_sdio_memcpy_toio(struct hwbus_priv * self,unsigned int addr,const void * src,int count)67*4882a593Smuzhiyun static int cw1200_sdio_memcpy_toio(struct hwbus_priv *self,
68*4882a593Smuzhiyun 				   unsigned int addr,
69*4882a593Smuzhiyun 				   const void *src, int count)
70*4882a593Smuzhiyun {
71*4882a593Smuzhiyun 	return sdio_memcpy_toio(self->func, addr, (void *)src, count);
72*4882a593Smuzhiyun }
73*4882a593Smuzhiyun 
cw1200_sdio_lock(struct hwbus_priv * self)74*4882a593Smuzhiyun static void cw1200_sdio_lock(struct hwbus_priv *self)
75*4882a593Smuzhiyun {
76*4882a593Smuzhiyun 	sdio_claim_host(self->func);
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun 
cw1200_sdio_unlock(struct hwbus_priv * self)79*4882a593Smuzhiyun static void cw1200_sdio_unlock(struct hwbus_priv *self)
80*4882a593Smuzhiyun {
81*4882a593Smuzhiyun 	sdio_release_host(self->func);
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun 
cw1200_sdio_irq_handler(struct sdio_func * func)84*4882a593Smuzhiyun static void cw1200_sdio_irq_handler(struct sdio_func *func)
85*4882a593Smuzhiyun {
86*4882a593Smuzhiyun 	struct hwbus_priv *self = sdio_get_drvdata(func);
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun 	/* note:  sdio_host already claimed here. */
89*4882a593Smuzhiyun 	if (self->core)
90*4882a593Smuzhiyun 		cw1200_irq_handler(self->core);
91*4882a593Smuzhiyun }
92*4882a593Smuzhiyun 
cw1200_gpio_hardirq(int irq,void * dev_id)93*4882a593Smuzhiyun static irqreturn_t cw1200_gpio_hardirq(int irq, void *dev_id)
94*4882a593Smuzhiyun {
95*4882a593Smuzhiyun 	return IRQ_WAKE_THREAD;
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun 
cw1200_gpio_irq(int irq,void * dev_id)98*4882a593Smuzhiyun static irqreturn_t cw1200_gpio_irq(int irq, void *dev_id)
99*4882a593Smuzhiyun {
100*4882a593Smuzhiyun 	struct hwbus_priv *self = dev_id;
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 	if (self->core) {
103*4882a593Smuzhiyun 		cw1200_sdio_lock(self);
104*4882a593Smuzhiyun 		cw1200_irq_handler(self->core);
105*4882a593Smuzhiyun 		cw1200_sdio_unlock(self);
106*4882a593Smuzhiyun 		return IRQ_HANDLED;
107*4882a593Smuzhiyun 	} else {
108*4882a593Smuzhiyun 		return IRQ_NONE;
109*4882a593Smuzhiyun 	}
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun 
cw1200_request_irq(struct hwbus_priv * self)112*4882a593Smuzhiyun static int cw1200_request_irq(struct hwbus_priv *self)
113*4882a593Smuzhiyun {
114*4882a593Smuzhiyun 	int ret;
115*4882a593Smuzhiyun 	u8 cccr;
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 	cccr = sdio_f0_readb(self->func, SDIO_CCCR_IENx, &ret);
118*4882a593Smuzhiyun 	if (WARN_ON(ret))
119*4882a593Smuzhiyun 		goto err;
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun 	/* Master interrupt enable ... */
122*4882a593Smuzhiyun 	cccr |= BIT(0);
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 	/* ... for our function */
125*4882a593Smuzhiyun 	cccr |= BIT(self->func->num);
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	sdio_f0_writeb(self->func, cccr, SDIO_CCCR_IENx, &ret);
128*4882a593Smuzhiyun 	if (WARN_ON(ret))
129*4882a593Smuzhiyun 		goto err;
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 	ret = enable_irq_wake(self->pdata->irq);
132*4882a593Smuzhiyun 	if (WARN_ON(ret))
133*4882a593Smuzhiyun 		goto err;
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	/* Request the IRQ */
136*4882a593Smuzhiyun 	ret =  request_threaded_irq(self->pdata->irq, cw1200_gpio_hardirq,
137*4882a593Smuzhiyun 				    cw1200_gpio_irq,
138*4882a593Smuzhiyun 				    IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
139*4882a593Smuzhiyun 				    "cw1200_wlan_irq", self);
140*4882a593Smuzhiyun 	if (WARN_ON(ret))
141*4882a593Smuzhiyun 		goto err;
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	return 0;
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun err:
146*4882a593Smuzhiyun 	return ret;
147*4882a593Smuzhiyun }
148*4882a593Smuzhiyun 
cw1200_sdio_irq_subscribe(struct hwbus_priv * self)149*4882a593Smuzhiyun static int cw1200_sdio_irq_subscribe(struct hwbus_priv *self)
150*4882a593Smuzhiyun {
151*4882a593Smuzhiyun 	int ret = 0;
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun 	pr_debug("SW IRQ subscribe\n");
154*4882a593Smuzhiyun 	sdio_claim_host(self->func);
155*4882a593Smuzhiyun 	if (self->pdata->irq)
156*4882a593Smuzhiyun 		ret = cw1200_request_irq(self);
157*4882a593Smuzhiyun 	else
158*4882a593Smuzhiyun 		ret = sdio_claim_irq(self->func, cw1200_sdio_irq_handler);
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 	sdio_release_host(self->func);
161*4882a593Smuzhiyun 	return ret;
162*4882a593Smuzhiyun }
163*4882a593Smuzhiyun 
cw1200_sdio_irq_unsubscribe(struct hwbus_priv * self)164*4882a593Smuzhiyun static int cw1200_sdio_irq_unsubscribe(struct hwbus_priv *self)
165*4882a593Smuzhiyun {
166*4882a593Smuzhiyun 	int ret = 0;
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun 	pr_debug("SW IRQ unsubscribe\n");
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 	if (self->pdata->irq) {
171*4882a593Smuzhiyun 		disable_irq_wake(self->pdata->irq);
172*4882a593Smuzhiyun 		free_irq(self->pdata->irq, self);
173*4882a593Smuzhiyun 	} else {
174*4882a593Smuzhiyun 		sdio_claim_host(self->func);
175*4882a593Smuzhiyun 		ret = sdio_release_irq(self->func);
176*4882a593Smuzhiyun 		sdio_release_host(self->func);
177*4882a593Smuzhiyun 	}
178*4882a593Smuzhiyun 	return ret;
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun 
cw1200_sdio_off(const struct cw1200_platform_data_sdio * pdata)181*4882a593Smuzhiyun static int cw1200_sdio_off(const struct cw1200_platform_data_sdio *pdata)
182*4882a593Smuzhiyun {
183*4882a593Smuzhiyun 	if (pdata->reset) {
184*4882a593Smuzhiyun 		gpio_set_value(pdata->reset, 0);
185*4882a593Smuzhiyun 		msleep(30); /* Min is 2 * CLK32K cycles */
186*4882a593Smuzhiyun 		gpio_free(pdata->reset);
187*4882a593Smuzhiyun 	}
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun 	if (pdata->power_ctrl)
190*4882a593Smuzhiyun 		pdata->power_ctrl(pdata, false);
191*4882a593Smuzhiyun 	if (pdata->clk_ctrl)
192*4882a593Smuzhiyun 		pdata->clk_ctrl(pdata, false);
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 	return 0;
195*4882a593Smuzhiyun }
196*4882a593Smuzhiyun 
cw1200_sdio_on(const struct cw1200_platform_data_sdio * pdata)197*4882a593Smuzhiyun static int cw1200_sdio_on(const struct cw1200_platform_data_sdio *pdata)
198*4882a593Smuzhiyun {
199*4882a593Smuzhiyun 	/* Ensure I/Os are pulled low */
200*4882a593Smuzhiyun 	if (pdata->reset) {
201*4882a593Smuzhiyun 		gpio_request(pdata->reset, "cw1200_wlan_reset");
202*4882a593Smuzhiyun 		gpio_direction_output(pdata->reset, 0);
203*4882a593Smuzhiyun 	}
204*4882a593Smuzhiyun 	if (pdata->powerup) {
205*4882a593Smuzhiyun 		gpio_request(pdata->powerup, "cw1200_wlan_powerup");
206*4882a593Smuzhiyun 		gpio_direction_output(pdata->powerup, 0);
207*4882a593Smuzhiyun 	}
208*4882a593Smuzhiyun 	if (pdata->reset || pdata->powerup)
209*4882a593Smuzhiyun 		msleep(10); /* Settle time? */
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun 	/* Enable 3v3 and 1v8 to hardware */
212*4882a593Smuzhiyun 	if (pdata->power_ctrl) {
213*4882a593Smuzhiyun 		if (pdata->power_ctrl(pdata, true)) {
214*4882a593Smuzhiyun 			pr_err("power_ctrl() failed!\n");
215*4882a593Smuzhiyun 			return -1;
216*4882a593Smuzhiyun 		}
217*4882a593Smuzhiyun 	}
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun 	/* Enable CLK32K */
220*4882a593Smuzhiyun 	if (pdata->clk_ctrl) {
221*4882a593Smuzhiyun 		if (pdata->clk_ctrl(pdata, true)) {
222*4882a593Smuzhiyun 			pr_err("clk_ctrl() failed!\n");
223*4882a593Smuzhiyun 			return -1;
224*4882a593Smuzhiyun 		}
225*4882a593Smuzhiyun 		msleep(10); /* Delay until clock is stable for 2 cycles */
226*4882a593Smuzhiyun 	}
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun 	/* Enable POWERUP signal */
229*4882a593Smuzhiyun 	if (pdata->powerup) {
230*4882a593Smuzhiyun 		gpio_set_value(pdata->powerup, 1);
231*4882a593Smuzhiyun 		msleep(250); /* or more..? */
232*4882a593Smuzhiyun 	}
233*4882a593Smuzhiyun 	/* Enable RSTn signal */
234*4882a593Smuzhiyun 	if (pdata->reset) {
235*4882a593Smuzhiyun 		gpio_set_value(pdata->reset, 1);
236*4882a593Smuzhiyun 		msleep(50); /* Or more..? */
237*4882a593Smuzhiyun 	}
238*4882a593Smuzhiyun 	return 0;
239*4882a593Smuzhiyun }
240*4882a593Smuzhiyun 
cw1200_sdio_align_size(struct hwbus_priv * self,size_t size)241*4882a593Smuzhiyun static size_t cw1200_sdio_align_size(struct hwbus_priv *self, size_t size)
242*4882a593Smuzhiyun {
243*4882a593Smuzhiyun 	if (self->pdata->no_nptb)
244*4882a593Smuzhiyun 		size = round_up(size, SDIO_BLOCK_SIZE);
245*4882a593Smuzhiyun 	else
246*4882a593Smuzhiyun 		size = sdio_align_size(self->func, size);
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun 	return size;
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun 
cw1200_sdio_pm(struct hwbus_priv * self,bool suspend)251*4882a593Smuzhiyun static int cw1200_sdio_pm(struct hwbus_priv *self, bool suspend)
252*4882a593Smuzhiyun {
253*4882a593Smuzhiyun 	int ret = 0;
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 	if (self->pdata->irq)
256*4882a593Smuzhiyun 		ret = irq_set_irq_wake(self->pdata->irq, suspend);
257*4882a593Smuzhiyun 	return ret;
258*4882a593Smuzhiyun }
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun static const struct hwbus_ops cw1200_sdio_hwbus_ops = {
261*4882a593Smuzhiyun 	.hwbus_memcpy_fromio	= cw1200_sdio_memcpy_fromio,
262*4882a593Smuzhiyun 	.hwbus_memcpy_toio	= cw1200_sdio_memcpy_toio,
263*4882a593Smuzhiyun 	.lock			= cw1200_sdio_lock,
264*4882a593Smuzhiyun 	.unlock			= cw1200_sdio_unlock,
265*4882a593Smuzhiyun 	.align_size		= cw1200_sdio_align_size,
266*4882a593Smuzhiyun 	.power_mgmt		= cw1200_sdio_pm,
267*4882a593Smuzhiyun };
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun /* Probe Function to be called by SDIO stack when device is discovered */
cw1200_sdio_probe(struct sdio_func * func,const struct sdio_device_id * id)270*4882a593Smuzhiyun static int cw1200_sdio_probe(struct sdio_func *func,
271*4882a593Smuzhiyun 			     const struct sdio_device_id *id)
272*4882a593Smuzhiyun {
273*4882a593Smuzhiyun 	struct hwbus_priv *self;
274*4882a593Smuzhiyun 	int status;
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun 	pr_info("cw1200_wlan_sdio: Probe called\n");
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun 	/* We are only able to handle the wlan function */
279*4882a593Smuzhiyun 	if (func->num != 0x01)
280*4882a593Smuzhiyun 		return -ENODEV;
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun 	self = kzalloc(sizeof(*self), GFP_KERNEL);
283*4882a593Smuzhiyun 	if (!self) {
284*4882a593Smuzhiyun 		pr_err("Can't allocate SDIO hwbus_priv.\n");
285*4882a593Smuzhiyun 		return -ENOMEM;
286*4882a593Smuzhiyun 	}
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun 	func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun 	self->pdata = global_plat_data; /* FIXME */
291*4882a593Smuzhiyun 	self->func = func;
292*4882a593Smuzhiyun 	sdio_set_drvdata(func, self);
293*4882a593Smuzhiyun 	sdio_claim_host(func);
294*4882a593Smuzhiyun 	sdio_enable_func(func);
295*4882a593Smuzhiyun 	sdio_release_host(func);
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun 	status = cw1200_sdio_irq_subscribe(self);
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun 	status = cw1200_core_probe(&cw1200_sdio_hwbus_ops,
300*4882a593Smuzhiyun 				   self, &func->dev, &self->core,
301*4882a593Smuzhiyun 				   self->pdata->ref_clk,
302*4882a593Smuzhiyun 				   self->pdata->macaddr,
303*4882a593Smuzhiyun 				   self->pdata->sdd_file,
304*4882a593Smuzhiyun 				   self->pdata->have_5ghz);
305*4882a593Smuzhiyun 	if (status) {
306*4882a593Smuzhiyun 		cw1200_sdio_irq_unsubscribe(self);
307*4882a593Smuzhiyun 		sdio_claim_host(func);
308*4882a593Smuzhiyun 		sdio_disable_func(func);
309*4882a593Smuzhiyun 		sdio_release_host(func);
310*4882a593Smuzhiyun 		sdio_set_drvdata(func, NULL);
311*4882a593Smuzhiyun 		kfree(self);
312*4882a593Smuzhiyun 	}
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun 	return status;
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun /* Disconnect Function to be called by SDIO stack when
318*4882a593Smuzhiyun  * device is disconnected
319*4882a593Smuzhiyun  */
cw1200_sdio_disconnect(struct sdio_func * func)320*4882a593Smuzhiyun static void cw1200_sdio_disconnect(struct sdio_func *func)
321*4882a593Smuzhiyun {
322*4882a593Smuzhiyun 	struct hwbus_priv *self = sdio_get_drvdata(func);
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun 	if (self) {
325*4882a593Smuzhiyun 		cw1200_sdio_irq_unsubscribe(self);
326*4882a593Smuzhiyun 		if (self->core) {
327*4882a593Smuzhiyun 			cw1200_core_release(self->core);
328*4882a593Smuzhiyun 			self->core = NULL;
329*4882a593Smuzhiyun 		}
330*4882a593Smuzhiyun 		sdio_claim_host(func);
331*4882a593Smuzhiyun 		sdio_disable_func(func);
332*4882a593Smuzhiyun 		sdio_release_host(func);
333*4882a593Smuzhiyun 		sdio_set_drvdata(func, NULL);
334*4882a593Smuzhiyun 		kfree(self);
335*4882a593Smuzhiyun 	}
336*4882a593Smuzhiyun }
337*4882a593Smuzhiyun 
338*4882a593Smuzhiyun #ifdef CONFIG_PM
cw1200_sdio_suspend(struct device * dev)339*4882a593Smuzhiyun static int cw1200_sdio_suspend(struct device *dev)
340*4882a593Smuzhiyun {
341*4882a593Smuzhiyun 	int ret;
342*4882a593Smuzhiyun 	struct sdio_func *func = dev_to_sdio_func(dev);
343*4882a593Smuzhiyun 	struct hwbus_priv *self = sdio_get_drvdata(func);
344*4882a593Smuzhiyun 
345*4882a593Smuzhiyun 	if (!cw1200_can_suspend(self->core))
346*4882a593Smuzhiyun 		return -EAGAIN;
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun 	/* Notify SDIO that CW1200 will remain powered during suspend */
349*4882a593Smuzhiyun 	ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
350*4882a593Smuzhiyun 	if (ret)
351*4882a593Smuzhiyun 		pr_err("Error setting SDIO pm flags: %i\n", ret);
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 	return ret;
354*4882a593Smuzhiyun }
355*4882a593Smuzhiyun 
cw1200_sdio_resume(struct device * dev)356*4882a593Smuzhiyun static int cw1200_sdio_resume(struct device *dev)
357*4882a593Smuzhiyun {
358*4882a593Smuzhiyun 	return 0;
359*4882a593Smuzhiyun }
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun static const struct dev_pm_ops cw1200_pm_ops = {
362*4882a593Smuzhiyun 	.suspend = cw1200_sdio_suspend,
363*4882a593Smuzhiyun 	.resume = cw1200_sdio_resume,
364*4882a593Smuzhiyun };
365*4882a593Smuzhiyun #endif
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun static struct sdio_driver sdio_driver = {
368*4882a593Smuzhiyun 	.name		= "cw1200_wlan_sdio",
369*4882a593Smuzhiyun 	.id_table	= cw1200_sdio_ids,
370*4882a593Smuzhiyun 	.probe		= cw1200_sdio_probe,
371*4882a593Smuzhiyun 	.remove		= cw1200_sdio_disconnect,
372*4882a593Smuzhiyun #ifdef CONFIG_PM
373*4882a593Smuzhiyun 	.drv = {
374*4882a593Smuzhiyun 		.pm = &cw1200_pm_ops,
375*4882a593Smuzhiyun 	}
376*4882a593Smuzhiyun #endif
377*4882a593Smuzhiyun };
378*4882a593Smuzhiyun 
379*4882a593Smuzhiyun /* Init Module function -> Called by insmod */
cw1200_sdio_init(void)380*4882a593Smuzhiyun static int __init cw1200_sdio_init(void)
381*4882a593Smuzhiyun {
382*4882a593Smuzhiyun 	const struct cw1200_platform_data_sdio *pdata;
383*4882a593Smuzhiyun 	int ret;
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun 	/* FIXME -- this won't support multiple devices */
386*4882a593Smuzhiyun 	pdata = global_plat_data;
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun 	if (cw1200_sdio_on(pdata)) {
389*4882a593Smuzhiyun 		ret = -1;
390*4882a593Smuzhiyun 		goto err;
391*4882a593Smuzhiyun 	}
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun 	ret = sdio_register_driver(&sdio_driver);
394*4882a593Smuzhiyun 	if (ret)
395*4882a593Smuzhiyun 		goto err;
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun 	return 0;
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun err:
400*4882a593Smuzhiyun 	cw1200_sdio_off(pdata);
401*4882a593Smuzhiyun 	return ret;
402*4882a593Smuzhiyun }
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun /* Called at Driver Unloading */
cw1200_sdio_exit(void)405*4882a593Smuzhiyun static void __exit cw1200_sdio_exit(void)
406*4882a593Smuzhiyun {
407*4882a593Smuzhiyun 	const struct cw1200_platform_data_sdio *pdata;
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun 	/* FIXME -- this won't support multiple devices */
410*4882a593Smuzhiyun 	pdata = global_plat_data;
411*4882a593Smuzhiyun 	sdio_unregister_driver(&sdio_driver);
412*4882a593Smuzhiyun 	cw1200_sdio_off(pdata);
413*4882a593Smuzhiyun }
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun module_init(cw1200_sdio_init);
417*4882a593Smuzhiyun module_exit(cw1200_sdio_exit);
418