1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * wl12xx SDIO routines
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2005 Texas Instruments Incorporated
6*4882a593Smuzhiyun * Copyright (C) 2008 Google Inc
7*4882a593Smuzhiyun * Copyright (C) 2009 Bob Copeland (me@bobcopeland.com)
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun #include <linux/interrupt.h>
10*4882a593Smuzhiyun #include <linux/module.h>
11*4882a593Smuzhiyun #include <linux/mod_devicetable.h>
12*4882a593Smuzhiyun #include <linux/mmc/sdio_func.h>
13*4882a593Smuzhiyun #include <linux/mmc/sdio_ids.h>
14*4882a593Smuzhiyun #include <linux/platform_device.h>
15*4882a593Smuzhiyun #include <linux/wl12xx.h>
16*4882a593Smuzhiyun #include <linux/irq.h>
17*4882a593Smuzhiyun #include <linux/pm_runtime.h>
18*4882a593Smuzhiyun #include <linux/of.h>
19*4882a593Smuzhiyun #include <linux/of_irq.h>
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun #include "wl1251.h"
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun struct wl1251_sdio {
24*4882a593Smuzhiyun struct sdio_func *func;
25*4882a593Smuzhiyun u32 elp_val;
26*4882a593Smuzhiyun };
27*4882a593Smuzhiyun
wl_to_func(struct wl1251 * wl)28*4882a593Smuzhiyun static struct sdio_func *wl_to_func(struct wl1251 *wl)
29*4882a593Smuzhiyun {
30*4882a593Smuzhiyun struct wl1251_sdio *wl_sdio = wl->if_priv;
31*4882a593Smuzhiyun return wl_sdio->func;
32*4882a593Smuzhiyun }
33*4882a593Smuzhiyun
wl1251_sdio_interrupt(struct sdio_func * func)34*4882a593Smuzhiyun static void wl1251_sdio_interrupt(struct sdio_func *func)
35*4882a593Smuzhiyun {
36*4882a593Smuzhiyun struct wl1251 *wl = sdio_get_drvdata(func);
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun wl1251_debug(DEBUG_IRQ, "IRQ");
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun /* FIXME should be synchronous for sdio */
41*4882a593Smuzhiyun ieee80211_queue_work(wl->hw, &wl->irq_work);
42*4882a593Smuzhiyun }
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun static const struct sdio_device_id wl1251_devices[] = {
45*4882a593Smuzhiyun { SDIO_DEVICE(SDIO_VENDOR_ID_TI_WL1251, SDIO_DEVICE_ID_TI_WL1251) },
46*4882a593Smuzhiyun {}
47*4882a593Smuzhiyun };
48*4882a593Smuzhiyun MODULE_DEVICE_TABLE(sdio, wl1251_devices);
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun
wl1251_sdio_read(struct wl1251 * wl,int addr,void * buf,size_t len)51*4882a593Smuzhiyun static void wl1251_sdio_read(struct wl1251 *wl, int addr,
52*4882a593Smuzhiyun void *buf, size_t len)
53*4882a593Smuzhiyun {
54*4882a593Smuzhiyun int ret;
55*4882a593Smuzhiyun struct sdio_func *func = wl_to_func(wl);
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun sdio_claim_host(func);
58*4882a593Smuzhiyun ret = sdio_memcpy_fromio(func, buf, addr, len);
59*4882a593Smuzhiyun if (ret)
60*4882a593Smuzhiyun wl1251_error("sdio read failed (%d)", ret);
61*4882a593Smuzhiyun sdio_release_host(func);
62*4882a593Smuzhiyun }
63*4882a593Smuzhiyun
wl1251_sdio_write(struct wl1251 * wl,int addr,void * buf,size_t len)64*4882a593Smuzhiyun static void wl1251_sdio_write(struct wl1251 *wl, int addr,
65*4882a593Smuzhiyun void *buf, size_t len)
66*4882a593Smuzhiyun {
67*4882a593Smuzhiyun int ret;
68*4882a593Smuzhiyun struct sdio_func *func = wl_to_func(wl);
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun sdio_claim_host(func);
71*4882a593Smuzhiyun ret = sdio_memcpy_toio(func, addr, buf, len);
72*4882a593Smuzhiyun if (ret)
73*4882a593Smuzhiyun wl1251_error("sdio write failed (%d)", ret);
74*4882a593Smuzhiyun sdio_release_host(func);
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun
wl1251_sdio_read_elp(struct wl1251 * wl,int addr,u32 * val)77*4882a593Smuzhiyun static void wl1251_sdio_read_elp(struct wl1251 *wl, int addr, u32 *val)
78*4882a593Smuzhiyun {
79*4882a593Smuzhiyun int ret = 0;
80*4882a593Smuzhiyun struct wl1251_sdio *wl_sdio = wl->if_priv;
81*4882a593Smuzhiyun struct sdio_func *func = wl_sdio->func;
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun /*
84*4882a593Smuzhiyun * The hardware only supports RAW (read after write) access for
85*4882a593Smuzhiyun * reading, regular sdio_readb won't work here (it interprets
86*4882a593Smuzhiyun * the unused bits of CMD52 as write data even if we send read
87*4882a593Smuzhiyun * request).
88*4882a593Smuzhiyun */
89*4882a593Smuzhiyun sdio_claim_host(func);
90*4882a593Smuzhiyun *val = sdio_writeb_readb(func, wl_sdio->elp_val, addr, &ret);
91*4882a593Smuzhiyun sdio_release_host(func);
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun if (ret)
94*4882a593Smuzhiyun wl1251_error("sdio_readb failed (%d)", ret);
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun
wl1251_sdio_write_elp(struct wl1251 * wl,int addr,u32 val)97*4882a593Smuzhiyun static void wl1251_sdio_write_elp(struct wl1251 *wl, int addr, u32 val)
98*4882a593Smuzhiyun {
99*4882a593Smuzhiyun int ret = 0;
100*4882a593Smuzhiyun struct wl1251_sdio *wl_sdio = wl->if_priv;
101*4882a593Smuzhiyun struct sdio_func *func = wl_sdio->func;
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun sdio_claim_host(func);
104*4882a593Smuzhiyun sdio_writeb(func, val, addr, &ret);
105*4882a593Smuzhiyun sdio_release_host(func);
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun if (ret)
108*4882a593Smuzhiyun wl1251_error("sdio_writeb failed (%d)", ret);
109*4882a593Smuzhiyun else
110*4882a593Smuzhiyun wl_sdio->elp_val = val;
111*4882a593Smuzhiyun }
112*4882a593Smuzhiyun
wl1251_sdio_reset(struct wl1251 * wl)113*4882a593Smuzhiyun static void wl1251_sdio_reset(struct wl1251 *wl)
114*4882a593Smuzhiyun {
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun
wl1251_sdio_enable_irq(struct wl1251 * wl)117*4882a593Smuzhiyun static void wl1251_sdio_enable_irq(struct wl1251 *wl)
118*4882a593Smuzhiyun {
119*4882a593Smuzhiyun struct sdio_func *func = wl_to_func(wl);
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun sdio_claim_host(func);
122*4882a593Smuzhiyun sdio_claim_irq(func, wl1251_sdio_interrupt);
123*4882a593Smuzhiyun sdio_release_host(func);
124*4882a593Smuzhiyun }
125*4882a593Smuzhiyun
wl1251_sdio_disable_irq(struct wl1251 * wl)126*4882a593Smuzhiyun static void wl1251_sdio_disable_irq(struct wl1251 *wl)
127*4882a593Smuzhiyun {
128*4882a593Smuzhiyun struct sdio_func *func = wl_to_func(wl);
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun sdio_claim_host(func);
131*4882a593Smuzhiyun sdio_release_irq(func);
132*4882a593Smuzhiyun sdio_release_host(func);
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun /* Interrupts when using dedicated WLAN_IRQ pin */
wl1251_line_irq(int irq,void * cookie)136*4882a593Smuzhiyun static irqreturn_t wl1251_line_irq(int irq, void *cookie)
137*4882a593Smuzhiyun {
138*4882a593Smuzhiyun struct wl1251 *wl = cookie;
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun ieee80211_queue_work(wl->hw, &wl->irq_work);
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun return IRQ_HANDLED;
143*4882a593Smuzhiyun }
144*4882a593Smuzhiyun
wl1251_enable_line_irq(struct wl1251 * wl)145*4882a593Smuzhiyun static void wl1251_enable_line_irq(struct wl1251 *wl)
146*4882a593Smuzhiyun {
147*4882a593Smuzhiyun return enable_irq(wl->irq);
148*4882a593Smuzhiyun }
149*4882a593Smuzhiyun
wl1251_disable_line_irq(struct wl1251 * wl)150*4882a593Smuzhiyun static void wl1251_disable_line_irq(struct wl1251 *wl)
151*4882a593Smuzhiyun {
152*4882a593Smuzhiyun return disable_irq(wl->irq);
153*4882a593Smuzhiyun }
154*4882a593Smuzhiyun
wl1251_sdio_set_power(struct wl1251 * wl,bool enable)155*4882a593Smuzhiyun static int wl1251_sdio_set_power(struct wl1251 *wl, bool enable)
156*4882a593Smuzhiyun {
157*4882a593Smuzhiyun struct sdio_func *func = wl_to_func(wl);
158*4882a593Smuzhiyun int ret;
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun if (enable) {
161*4882a593Smuzhiyun ret = pm_runtime_get_sync(&func->dev);
162*4882a593Smuzhiyun if (ret < 0) {
163*4882a593Smuzhiyun pm_runtime_put_sync(&func->dev);
164*4882a593Smuzhiyun goto out;
165*4882a593Smuzhiyun }
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun sdio_claim_host(func);
168*4882a593Smuzhiyun sdio_enable_func(func);
169*4882a593Smuzhiyun sdio_release_host(func);
170*4882a593Smuzhiyun } else {
171*4882a593Smuzhiyun sdio_claim_host(func);
172*4882a593Smuzhiyun sdio_disable_func(func);
173*4882a593Smuzhiyun sdio_release_host(func);
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun ret = pm_runtime_put_sync(&func->dev);
176*4882a593Smuzhiyun if (ret < 0)
177*4882a593Smuzhiyun goto out;
178*4882a593Smuzhiyun }
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun out:
181*4882a593Smuzhiyun return ret;
182*4882a593Smuzhiyun }
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun static struct wl1251_if_operations wl1251_sdio_ops = {
185*4882a593Smuzhiyun .read = wl1251_sdio_read,
186*4882a593Smuzhiyun .write = wl1251_sdio_write,
187*4882a593Smuzhiyun .write_elp = wl1251_sdio_write_elp,
188*4882a593Smuzhiyun .read_elp = wl1251_sdio_read_elp,
189*4882a593Smuzhiyun .reset = wl1251_sdio_reset,
190*4882a593Smuzhiyun .power = wl1251_sdio_set_power,
191*4882a593Smuzhiyun };
192*4882a593Smuzhiyun
wl1251_sdio_probe(struct sdio_func * func,const struct sdio_device_id * id)193*4882a593Smuzhiyun static int wl1251_sdio_probe(struct sdio_func *func,
194*4882a593Smuzhiyun const struct sdio_device_id *id)
195*4882a593Smuzhiyun {
196*4882a593Smuzhiyun int ret;
197*4882a593Smuzhiyun struct wl1251 *wl;
198*4882a593Smuzhiyun struct ieee80211_hw *hw;
199*4882a593Smuzhiyun struct wl1251_sdio *wl_sdio;
200*4882a593Smuzhiyun const struct wl1251_platform_data *wl1251_board_data;
201*4882a593Smuzhiyun struct device_node *np = func->dev.of_node;
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun hw = wl1251_alloc_hw();
204*4882a593Smuzhiyun if (IS_ERR(hw))
205*4882a593Smuzhiyun return PTR_ERR(hw);
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun wl = hw->priv;
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun wl_sdio = kzalloc(sizeof(*wl_sdio), GFP_KERNEL);
210*4882a593Smuzhiyun if (wl_sdio == NULL) {
211*4882a593Smuzhiyun ret = -ENOMEM;
212*4882a593Smuzhiyun goto out_free_hw;
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun sdio_claim_host(func);
216*4882a593Smuzhiyun ret = sdio_enable_func(func);
217*4882a593Smuzhiyun if (ret)
218*4882a593Smuzhiyun goto release;
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun sdio_set_block_size(func, 512);
221*4882a593Smuzhiyun sdio_release_host(func);
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun SET_IEEE80211_DEV(hw, &func->dev);
224*4882a593Smuzhiyun wl_sdio->func = func;
225*4882a593Smuzhiyun wl->if_priv = wl_sdio;
226*4882a593Smuzhiyun wl->if_ops = &wl1251_sdio_ops;
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun wl1251_board_data = wl1251_get_platform_data();
229*4882a593Smuzhiyun if (!IS_ERR(wl1251_board_data)) {
230*4882a593Smuzhiyun wl->irq = wl1251_board_data->irq;
231*4882a593Smuzhiyun wl->use_eeprom = wl1251_board_data->use_eeprom;
232*4882a593Smuzhiyun } else if (np) {
233*4882a593Smuzhiyun wl->use_eeprom = of_property_read_bool(np, "ti,wl1251-has-eeprom");
234*4882a593Smuzhiyun wl->irq = of_irq_get(np, 0);
235*4882a593Smuzhiyun if (wl->irq == -EPROBE_DEFER) {
236*4882a593Smuzhiyun ret = -EPROBE_DEFER;
237*4882a593Smuzhiyun goto disable;
238*4882a593Smuzhiyun }
239*4882a593Smuzhiyun }
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun if (wl->irq) {
242*4882a593Smuzhiyun irq_set_status_flags(wl->irq, IRQ_NOAUTOEN);
243*4882a593Smuzhiyun ret = request_irq(wl->irq, wl1251_line_irq, 0, "wl1251", wl);
244*4882a593Smuzhiyun if (ret < 0) {
245*4882a593Smuzhiyun wl1251_error("request_irq() failed: %d", ret);
246*4882a593Smuzhiyun goto disable;
247*4882a593Smuzhiyun }
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun irq_set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING);
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun wl1251_sdio_ops.enable_irq = wl1251_enable_line_irq;
252*4882a593Smuzhiyun wl1251_sdio_ops.disable_irq = wl1251_disable_line_irq;
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun wl1251_info("using dedicated interrupt line");
255*4882a593Smuzhiyun } else {
256*4882a593Smuzhiyun wl1251_sdio_ops.enable_irq = wl1251_sdio_enable_irq;
257*4882a593Smuzhiyun wl1251_sdio_ops.disable_irq = wl1251_sdio_disable_irq;
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun wl1251_info("using SDIO interrupt");
260*4882a593Smuzhiyun }
261*4882a593Smuzhiyun
262*4882a593Smuzhiyun ret = wl1251_init_ieee80211(wl);
263*4882a593Smuzhiyun if (ret)
264*4882a593Smuzhiyun goto out_free_irq;
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun sdio_set_drvdata(func, wl);
267*4882a593Smuzhiyun
268*4882a593Smuzhiyun /* Tell PM core that we don't need the card to be powered now */
269*4882a593Smuzhiyun pm_runtime_put_noidle(&func->dev);
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun return ret;
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun out_free_irq:
274*4882a593Smuzhiyun if (wl->irq)
275*4882a593Smuzhiyun free_irq(wl->irq, wl);
276*4882a593Smuzhiyun disable:
277*4882a593Smuzhiyun sdio_claim_host(func);
278*4882a593Smuzhiyun sdio_disable_func(func);
279*4882a593Smuzhiyun release:
280*4882a593Smuzhiyun sdio_release_host(func);
281*4882a593Smuzhiyun kfree(wl_sdio);
282*4882a593Smuzhiyun out_free_hw:
283*4882a593Smuzhiyun wl1251_free_hw(wl);
284*4882a593Smuzhiyun return ret;
285*4882a593Smuzhiyun }
286*4882a593Smuzhiyun
wl1251_sdio_remove(struct sdio_func * func)287*4882a593Smuzhiyun static void wl1251_sdio_remove(struct sdio_func *func)
288*4882a593Smuzhiyun {
289*4882a593Smuzhiyun struct wl1251 *wl = sdio_get_drvdata(func);
290*4882a593Smuzhiyun struct wl1251_sdio *wl_sdio = wl->if_priv;
291*4882a593Smuzhiyun
292*4882a593Smuzhiyun /* Undo decrement done above in wl1251_probe */
293*4882a593Smuzhiyun pm_runtime_get_noresume(&func->dev);
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun if (wl->irq)
296*4882a593Smuzhiyun free_irq(wl->irq, wl);
297*4882a593Smuzhiyun wl1251_free_hw(wl);
298*4882a593Smuzhiyun kfree(wl_sdio);
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun sdio_claim_host(func);
301*4882a593Smuzhiyun sdio_release_irq(func);
302*4882a593Smuzhiyun sdio_disable_func(func);
303*4882a593Smuzhiyun sdio_release_host(func);
304*4882a593Smuzhiyun }
305*4882a593Smuzhiyun
wl1251_suspend(struct device * dev)306*4882a593Smuzhiyun static int wl1251_suspend(struct device *dev)
307*4882a593Smuzhiyun {
308*4882a593Smuzhiyun /*
309*4882a593Smuzhiyun * Tell MMC/SDIO core it's OK to power down the card
310*4882a593Smuzhiyun * (if it isn't already), but not to remove it completely.
311*4882a593Smuzhiyun */
312*4882a593Smuzhiyun return 0;
313*4882a593Smuzhiyun }
314*4882a593Smuzhiyun
wl1251_resume(struct device * dev)315*4882a593Smuzhiyun static int wl1251_resume(struct device *dev)
316*4882a593Smuzhiyun {
317*4882a593Smuzhiyun return 0;
318*4882a593Smuzhiyun }
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun static const struct dev_pm_ops wl1251_sdio_pm_ops = {
321*4882a593Smuzhiyun .suspend = wl1251_suspend,
322*4882a593Smuzhiyun .resume = wl1251_resume,
323*4882a593Smuzhiyun };
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun static struct sdio_driver wl1251_sdio_driver = {
326*4882a593Smuzhiyun .name = "wl1251_sdio",
327*4882a593Smuzhiyun .id_table = wl1251_devices,
328*4882a593Smuzhiyun .probe = wl1251_sdio_probe,
329*4882a593Smuzhiyun .remove = wl1251_sdio_remove,
330*4882a593Smuzhiyun .drv.pm = &wl1251_sdio_pm_ops,
331*4882a593Smuzhiyun };
332*4882a593Smuzhiyun
wl1251_sdio_init(void)333*4882a593Smuzhiyun static int __init wl1251_sdio_init(void)
334*4882a593Smuzhiyun {
335*4882a593Smuzhiyun int err;
336*4882a593Smuzhiyun
337*4882a593Smuzhiyun err = sdio_register_driver(&wl1251_sdio_driver);
338*4882a593Smuzhiyun if (err)
339*4882a593Smuzhiyun wl1251_error("failed to register sdio driver: %d", err);
340*4882a593Smuzhiyun return err;
341*4882a593Smuzhiyun }
342*4882a593Smuzhiyun
wl1251_sdio_exit(void)343*4882a593Smuzhiyun static void __exit wl1251_sdio_exit(void)
344*4882a593Smuzhiyun {
345*4882a593Smuzhiyun sdio_unregister_driver(&wl1251_sdio_driver);
346*4882a593Smuzhiyun wl1251_notice("unloaded");
347*4882a593Smuzhiyun }
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun module_init(wl1251_sdio_init);
350*4882a593Smuzhiyun module_exit(wl1251_sdio_exit);
351*4882a593Smuzhiyun
352*4882a593Smuzhiyun MODULE_LICENSE("GPL");
353*4882a593Smuzhiyun MODULE_AUTHOR("Kalle Valo <kvalo@adurom.com>");
354