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