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