xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/ti/wl1251/sdio.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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