• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/drivers/net/wireless/wl12xx/
1/*
2 * This file is part of wl1251
3 *
4 * Copyright (C) 2008 Nokia Corporation
5 *
6 * Contact: Kalle Valo <kalle.valo@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/irq.h>
25#include <linux/module.h>
26#include <linux/slab.h>
27#include <linux/crc7.h>
28#include <linux/spi/spi.h>
29#include <linux/spi/wl12xx.h>
30
31#include "wl1251.h"
32#include "wl1251_reg.h"
33#include "wl1251_spi.h"
34
35static irqreturn_t wl1251_irq(int irq, void *cookie)
36{
37	struct wl1251 *wl;
38
39	wl1251_debug(DEBUG_IRQ, "IRQ");
40
41	wl = cookie;
42
43	ieee80211_queue_work(wl->hw, &wl->irq_work);
44
45	return IRQ_HANDLED;
46}
47
48static struct spi_device *wl_to_spi(struct wl1251 *wl)
49{
50	return wl->if_priv;
51}
52
53static void wl1251_spi_reset(struct wl1251 *wl)
54{
55	u8 *cmd;
56	struct spi_transfer t;
57	struct spi_message m;
58
59	cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL);
60	if (!cmd) {
61		wl1251_error("could not allocate cmd for spi reset");
62		return;
63	}
64
65	memset(&t, 0, sizeof(t));
66	spi_message_init(&m);
67
68	memset(cmd, 0xff, WSPI_INIT_CMD_LEN);
69
70	t.tx_buf = cmd;
71	t.len = WSPI_INIT_CMD_LEN;
72	spi_message_add_tail(&t, &m);
73
74	spi_sync(wl_to_spi(wl), &m);
75
76	wl1251_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN);
77}
78
79static void wl1251_spi_wake(struct wl1251 *wl)
80{
81	u8 crc[WSPI_INIT_CMD_CRC_LEN], *cmd;
82	struct spi_transfer t;
83	struct spi_message m;
84
85	cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL);
86	if (!cmd) {
87		wl1251_error("could not allocate cmd for spi init");
88		return;
89	}
90
91	memset(crc, 0, sizeof(crc));
92	memset(&t, 0, sizeof(t));
93	spi_message_init(&m);
94
95	/*
96	 * Set WSPI_INIT_COMMAND
97	 * the data is being send from the MSB to LSB
98	 */
99	cmd[2] = 0xff;
100	cmd[3] = 0xff;
101	cmd[1] = WSPI_INIT_CMD_START | WSPI_INIT_CMD_TX;
102	cmd[0] = 0;
103	cmd[7] = 0;
104	cmd[6] |= HW_ACCESS_WSPI_INIT_CMD_MASK << 3;
105	cmd[6] |= HW_ACCESS_WSPI_FIXED_BUSY_LEN & WSPI_INIT_CMD_FIXEDBUSY_LEN;
106
107	if (HW_ACCESS_WSPI_FIXED_BUSY_LEN == 0)
108		cmd[5] |=  WSPI_INIT_CMD_DIS_FIXEDBUSY;
109	else
110		cmd[5] |= WSPI_INIT_CMD_EN_FIXEDBUSY;
111
112	cmd[5] |= WSPI_INIT_CMD_IOD | WSPI_INIT_CMD_IP | WSPI_INIT_CMD_CS
113		| WSPI_INIT_CMD_WSPI | WSPI_INIT_CMD_WS;
114
115	crc[0] = cmd[1];
116	crc[1] = cmd[0];
117	crc[2] = cmd[7];
118	crc[3] = cmd[6];
119	crc[4] = cmd[5];
120
121	cmd[4] |= crc7(0, crc, WSPI_INIT_CMD_CRC_LEN) << 1;
122	cmd[4] |= WSPI_INIT_CMD_END;
123
124	t.tx_buf = cmd;
125	t.len = WSPI_INIT_CMD_LEN;
126	spi_message_add_tail(&t, &m);
127
128	spi_sync(wl_to_spi(wl), &m);
129
130	wl1251_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN);
131}
132
133static void wl1251_spi_reset_wake(struct wl1251 *wl)
134{
135	wl1251_spi_reset(wl);
136	wl1251_spi_wake(wl);
137}
138
139static void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf,
140			    size_t len)
141{
142	struct spi_transfer t[3];
143	struct spi_message m;
144	u8 *busy_buf;
145	u32 *cmd;
146
147	cmd = &wl->buffer_cmd;
148	busy_buf = wl->buffer_busyword;
149
150	*cmd = 0;
151	*cmd |= WSPI_CMD_READ;
152	*cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH;
153	*cmd |= addr & WSPI_CMD_BYTE_ADDR;
154
155	spi_message_init(&m);
156	memset(t, 0, sizeof(t));
157
158	t[0].tx_buf = cmd;
159	t[0].len = 4;
160	spi_message_add_tail(&t[0], &m);
161
162	/* Busy and non busy words read */
163	t[1].rx_buf = busy_buf;
164	t[1].len = WL1251_BUSY_WORD_LEN;
165	spi_message_add_tail(&t[1], &m);
166
167	t[2].rx_buf = buf;
168	t[2].len = len;
169	spi_message_add_tail(&t[2], &m);
170
171	spi_sync(wl_to_spi(wl), &m);
172
173
174	wl1251_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd));
175	wl1251_dump(DEBUG_SPI, "spi_read buf <- ", buf, len);
176}
177
178static void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf,
179			     size_t len)
180{
181	struct spi_transfer t[2];
182	struct spi_message m;
183	u32 *cmd;
184
185	cmd = &wl->buffer_cmd;
186
187	*cmd = 0;
188	*cmd |= WSPI_CMD_WRITE;
189	*cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH;
190	*cmd |= addr & WSPI_CMD_BYTE_ADDR;
191
192	spi_message_init(&m);
193	memset(t, 0, sizeof(t));
194
195	t[0].tx_buf = cmd;
196	t[0].len = sizeof(*cmd);
197	spi_message_add_tail(&t[0], &m);
198
199	t[1].tx_buf = buf;
200	t[1].len = len;
201	spi_message_add_tail(&t[1], &m);
202
203	spi_sync(wl_to_spi(wl), &m);
204
205	wl1251_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd));
206	wl1251_dump(DEBUG_SPI, "spi_write buf -> ", buf, len);
207}
208
209static void wl1251_spi_enable_irq(struct wl1251 *wl)
210{
211	return enable_irq(wl->irq);
212}
213
214static void wl1251_spi_disable_irq(struct wl1251 *wl)
215{
216	return disable_irq(wl->irq);
217}
218
219static const struct wl1251_if_operations wl1251_spi_ops = {
220	.read = wl1251_spi_read,
221	.write = wl1251_spi_write,
222	.reset = wl1251_spi_reset_wake,
223	.enable_irq = wl1251_spi_enable_irq,
224	.disable_irq = wl1251_spi_disable_irq,
225};
226
227static int __devinit wl1251_spi_probe(struct spi_device *spi)
228{
229	struct wl12xx_platform_data *pdata;
230	struct ieee80211_hw *hw;
231	struct wl1251 *wl;
232	int ret;
233
234	pdata = spi->dev.platform_data;
235	if (!pdata) {
236		wl1251_error("no platform data");
237		return -ENODEV;
238	}
239
240	hw = wl1251_alloc_hw();
241	if (IS_ERR(hw))
242		return PTR_ERR(hw);
243
244	wl = hw->priv;
245
246	SET_IEEE80211_DEV(hw, &spi->dev);
247	dev_set_drvdata(&spi->dev, wl);
248	wl->if_priv = spi;
249	wl->if_ops = &wl1251_spi_ops;
250
251	/* This is the only SPI value that we need to set here, the rest
252	 * comes from the board-peripherals file */
253	spi->bits_per_word = 32;
254
255	ret = spi_setup(spi);
256	if (ret < 0) {
257		wl1251_error("spi_setup failed");
258		goto out_free;
259	}
260
261	wl->set_power = pdata->set_power;
262	if (!wl->set_power) {
263		wl1251_error("set power function missing in platform data");
264		return -ENODEV;
265	}
266
267	wl->irq = spi->irq;
268	if (wl->irq < 0) {
269		wl1251_error("irq missing in platform data");
270		return -ENODEV;
271	}
272
273	wl->use_eeprom = pdata->use_eeprom;
274
275	ret = request_irq(wl->irq, wl1251_irq, 0, DRIVER_NAME, wl);
276	if (ret < 0) {
277		wl1251_error("request_irq() failed: %d", ret);
278		goto out_free;
279	}
280
281	set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING);
282
283	disable_irq(wl->irq);
284
285	ret = wl1251_init_ieee80211(wl);
286	if (ret)
287		goto out_irq;
288
289	return 0;
290
291 out_irq:
292	free_irq(wl->irq, wl);
293
294 out_free:
295	ieee80211_free_hw(hw);
296
297	return ret;
298}
299
300static int __devexit wl1251_spi_remove(struct spi_device *spi)
301{
302	struct wl1251 *wl = dev_get_drvdata(&spi->dev);
303
304	free_irq(wl->irq, wl);
305	wl1251_free_hw(wl);
306
307	return 0;
308}
309
310static struct spi_driver wl1251_spi_driver = {
311	.driver = {
312		.name		= DRIVER_NAME,
313		.bus		= &spi_bus_type,
314		.owner		= THIS_MODULE,
315	},
316
317	.probe		= wl1251_spi_probe,
318	.remove		= __devexit_p(wl1251_spi_remove),
319};
320
321static int __init wl1251_spi_init(void)
322{
323	int ret;
324
325	ret = spi_register_driver(&wl1251_spi_driver);
326	if (ret < 0) {
327		wl1251_error("failed to register spi driver: %d", ret);
328		goto out;
329	}
330
331out:
332	return ret;
333}
334
335static void __exit wl1251_spi_exit(void)
336{
337	spi_unregister_driver(&wl1251_spi_driver);
338
339	wl1251_notice("unloaded");
340}
341
342module_init(wl1251_spi_init);
343module_exit(wl1251_spi_exit);
344
345MODULE_LICENSE("GPL");
346MODULE_AUTHOR("Kalle Valo <kalle.valo@nokia.com>");
347MODULE_ALIAS("spi:wl1251");
348