blob: 5967317ef02543f8b0a06cbbaa63fcd6f2b4e00f [file] [log] [blame]
Kalle Valo2f01a1f2009-04-29 23:33:31 +03001/*
Kalle Valo80301cd2009-06-12 14:17:39 +03002 * This file is part of wl1251
Kalle Valo2f01a1f2009-04-29 23:33:31 +03003 *
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
Bob Copeland8e639c02009-08-07 13:33:26 +030024#include <linux/irq.h>
Kalle Valo2f01a1f2009-04-29 23:33:31 +030025#include <linux/module.h>
26#include <linux/crc7.h>
27#include <linux/spi/spi.h>
Bob Copeland8e639c02009-08-07 13:33:26 +030028#include <linux/spi/wl12xx.h>
Kalle Valo2f01a1f2009-04-29 23:33:31 +030029
Kalle Valo13674112009-06-12 14:17:25 +030030#include "wl1251.h"
Kalle Valo2f01a1f2009-04-29 23:33:31 +030031#include "reg.h"
Kalle Valoef2f8d42009-06-12 14:17:19 +030032#include "wl1251_spi.h"
Kalle Valo2f01a1f2009-04-29 23:33:31 +030033
Bob Copelandaf8c78e2009-08-07 13:33:34 +030034static struct spi_device *wl_to_spi(struct wl1251 *wl)
35{
36 return wl->if_priv;
37}
38
Bob Copeland08d9f5722009-08-07 13:33:11 +030039static void wl1251_spi_reset(struct wl1251 *wl)
Kalle Valo2f01a1f2009-04-29 23:33:31 +030040{
41 u8 *cmd;
42 struct spi_transfer t;
43 struct spi_message m;
44
45 cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL);
46 if (!cmd) {
Kalle Valo80301cd2009-06-12 14:17:39 +030047 wl1251_error("could not allocate cmd for spi reset");
Kalle Valo2f01a1f2009-04-29 23:33:31 +030048 return;
49 }
50
51 memset(&t, 0, sizeof(t));
52 spi_message_init(&m);
53
54 memset(cmd, 0xff, WSPI_INIT_CMD_LEN);
55
56 t.tx_buf = cmd;
57 t.len = WSPI_INIT_CMD_LEN;
58 spi_message_add_tail(&t, &m);
59
Bob Copelandaf8c78e2009-08-07 13:33:34 +030060 spi_sync(wl_to_spi(wl), &m);
Kalle Valo2f01a1f2009-04-29 23:33:31 +030061
Kalle Valo80301cd2009-06-12 14:17:39 +030062 wl1251_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN);
Kalle Valo2f01a1f2009-04-29 23:33:31 +030063}
64
Bob Copeland8e639c02009-08-07 13:33:26 +030065static void wl1251_spi_wake(struct wl1251 *wl)
Kalle Valo2f01a1f2009-04-29 23:33:31 +030066{
67 u8 crc[WSPI_INIT_CMD_CRC_LEN], *cmd;
68 struct spi_transfer t;
69 struct spi_message m;
70
71 cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL);
72 if (!cmd) {
Kalle Valo80301cd2009-06-12 14:17:39 +030073 wl1251_error("could not allocate cmd for spi init");
Kalle Valo2f01a1f2009-04-29 23:33:31 +030074 return;
75 }
76
77 memset(crc, 0, sizeof(crc));
78 memset(&t, 0, sizeof(t));
79 spi_message_init(&m);
80
81 /*
82 * Set WSPI_INIT_COMMAND
83 * the data is being send from the MSB to LSB
84 */
85 cmd[2] = 0xff;
86 cmd[3] = 0xff;
87 cmd[1] = WSPI_INIT_CMD_START | WSPI_INIT_CMD_TX;
88 cmd[0] = 0;
89 cmd[7] = 0;
90 cmd[6] |= HW_ACCESS_WSPI_INIT_CMD_MASK << 3;
91 cmd[6] |= HW_ACCESS_WSPI_FIXED_BUSY_LEN & WSPI_INIT_CMD_FIXEDBUSY_LEN;
92
93 if (HW_ACCESS_WSPI_FIXED_BUSY_LEN == 0)
94 cmd[5] |= WSPI_INIT_CMD_DIS_FIXEDBUSY;
95 else
96 cmd[5] |= WSPI_INIT_CMD_EN_FIXEDBUSY;
97
98 cmd[5] |= WSPI_INIT_CMD_IOD | WSPI_INIT_CMD_IP | WSPI_INIT_CMD_CS
99 | WSPI_INIT_CMD_WSPI | WSPI_INIT_CMD_WS;
100
101 crc[0] = cmd[1];
102 crc[1] = cmd[0];
103 crc[2] = cmd[7];
104 crc[3] = cmd[6];
105 crc[4] = cmd[5];
106
107 cmd[4] |= crc7(0, crc, WSPI_INIT_CMD_CRC_LEN) << 1;
108 cmd[4] |= WSPI_INIT_CMD_END;
109
110 t.tx_buf = cmd;
111 t.len = WSPI_INIT_CMD_LEN;
112 spi_message_add_tail(&t, &m);
113
Bob Copelandaf8c78e2009-08-07 13:33:34 +0300114 spi_sync(wl_to_spi(wl), &m);
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300115
Kalle Valo80301cd2009-06-12 14:17:39 +0300116 wl1251_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN);
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300117}
118
Bob Copeland08d9f5722009-08-07 13:33:11 +0300119static void wl1251_spi_reset_wake(struct wl1251 *wl)
120{
121 wl1251_spi_reset(wl);
Bob Copeland8e639c02009-08-07 13:33:26 +0300122 wl1251_spi_wake(wl);
Bob Copeland08d9f5722009-08-07 13:33:11 +0300123}
124
Bob Copeland08d9f5722009-08-07 13:33:11 +0300125static void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf,
126 size_t len)
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300127{
128 struct spi_transfer t[3];
129 struct spi_message m;
Kalle Valo5262c122009-06-12 14:14:55 +0300130 u8 *busy_buf;
Kalle Valo56343a32009-06-12 14:14:47 +0300131 u32 *cmd;
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300132
Kalle Valo56343a32009-06-12 14:14:47 +0300133 cmd = &wl->buffer_cmd;
Kalle Valo5262c122009-06-12 14:14:55 +0300134 busy_buf = wl->buffer_busyword;
Kalle Valo56343a32009-06-12 14:14:47 +0300135
136 *cmd = 0;
137 *cmd |= WSPI_CMD_READ;
138 *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH;
139 *cmd |= addr & WSPI_CMD_BYTE_ADDR;
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300140
141 spi_message_init(&m);
142 memset(t, 0, sizeof(t));
143
Kalle Valo56343a32009-06-12 14:14:47 +0300144 t[0].tx_buf = cmd;
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300145 t[0].len = 4;
146 spi_message_add_tail(&t[0], &m);
147
148 /* Busy and non busy words read */
149 t[1].rx_buf = busy_buf;
Kalle Valo80301cd2009-06-12 14:17:39 +0300150 t[1].len = WL1251_BUSY_WORD_LEN;
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300151 spi_message_add_tail(&t[1], &m);
152
153 t[2].rx_buf = buf;
154 t[2].len = len;
155 spi_message_add_tail(&t[2], &m);
156
Bob Copelandaf8c78e2009-08-07 13:33:34 +0300157 spi_sync(wl_to_spi(wl), &m);
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300158
159 /* FIXME: check busy words */
160
Kalle Valo80301cd2009-06-12 14:17:39 +0300161 wl1251_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd));
162 wl1251_dump(DEBUG_SPI, "spi_read buf <- ", buf, len);
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300163}
164
Bob Copeland08d9f5722009-08-07 13:33:11 +0300165static void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf,
166 size_t len)
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300167{
168 struct spi_transfer t[2];
169 struct spi_message m;
Kalle Valo56343a32009-06-12 14:14:47 +0300170 u32 *cmd;
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300171
Kalle Valo56343a32009-06-12 14:14:47 +0300172 cmd = &wl->buffer_cmd;
173
174 *cmd = 0;
175 *cmd |= WSPI_CMD_WRITE;
176 *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH;
177 *cmd |= addr & WSPI_CMD_BYTE_ADDR;
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300178
179 spi_message_init(&m);
180 memset(t, 0, sizeof(t));
181
Kalle Valo56343a32009-06-12 14:14:47 +0300182 t[0].tx_buf = cmd;
183 t[0].len = sizeof(*cmd);
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300184 spi_message_add_tail(&t[0], &m);
185
186 t[1].tx_buf = buf;
187 t[1].len = len;
188 spi_message_add_tail(&t[1], &m);
189
Bob Copelandaf8c78e2009-08-07 13:33:34 +0300190 spi_sync(wl_to_spi(wl), &m);
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300191
Kalle Valo80301cd2009-06-12 14:17:39 +0300192 wl1251_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd));
193 wl1251_dump(DEBUG_SPI, "spi_write buf -> ", buf, len);
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300194}
Bob Copeland08d9f5722009-08-07 13:33:11 +0300195
Bob Copelandaf8c78e2009-08-07 13:33:34 +0300196static const struct wl1251_if_operations wl1251_spi_ops = {
Bob Copeland08d9f5722009-08-07 13:33:11 +0300197 .read = wl1251_spi_read,
198 .write = wl1251_spi_write,
199 .reset = wl1251_spi_reset_wake,
200};
Bob Copeland8e639c02009-08-07 13:33:26 +0300201
202static int __devinit wl1251_spi_probe(struct spi_device *spi)
203{
204 struct wl12xx_platform_data *pdata;
205 struct ieee80211_hw *hw;
206 struct wl1251 *wl;
207 int ret;
208
209 pdata = spi->dev.platform_data;
210 if (!pdata) {
211 wl1251_error("no platform data");
212 return -ENODEV;
213 }
214
215 hw = wl1251_alloc_hw();
216 if (IS_ERR(hw))
217 return PTR_ERR(hw);
218
219 wl = hw->priv;
220
221 SET_IEEE80211_DEV(hw, &spi->dev);
222 dev_set_drvdata(&spi->dev, wl);
Bob Copelandaf8c78e2009-08-07 13:33:34 +0300223 wl->if_priv = spi;
Bob Copeland8e639c02009-08-07 13:33:26 +0300224 wl->if_ops = &wl1251_spi_ops;
225
226 /* This is the only SPI value that we need to set here, the rest
227 * comes from the board-peripherals file */
228 spi->bits_per_word = 32;
229
230 ret = spi_setup(spi);
231 if (ret < 0) {
232 wl1251_error("spi_setup failed");
233 goto out_free;
234 }
235
236 wl->set_power = pdata->set_power;
237 if (!wl->set_power) {
238 wl1251_error("set power function missing in platform data");
239 return -ENODEV;
240 }
241
242 wl->irq = spi->irq;
243 if (wl->irq < 0) {
244 wl1251_error("irq missing in platform data");
245 return -ENODEV;
246 }
247
248 ret = request_irq(wl->irq, wl1251_irq, 0, DRIVER_NAME, wl);
249 if (ret < 0) {
250 wl1251_error("request_irq() failed: %d", ret);
251 goto out_free;
252 }
253
254 set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING);
255
256 disable_irq(wl->irq);
257
258 ret = wl1251_init_ieee80211(wl);
259 if (ret)
260 goto out_irq;
261
262 return 0;
263
264 out_irq:
265 free_irq(wl->irq, wl);
266
267 out_free:
268 ieee80211_free_hw(hw);
269
270 return ret;
271}
272
273static int __devexit wl1251_spi_remove(struct spi_device *spi)
274{
275 struct wl1251 *wl = dev_get_drvdata(&spi->dev);
276
277 wl1251_free_hw(wl);
278
279 return 0;
280}
281
282static struct spi_driver wl1251_spi_driver = {
283 .driver = {
284 .name = "wl12xx",
285 .bus = &spi_bus_type,
286 .owner = THIS_MODULE,
287 },
288
289 .probe = wl1251_spi_probe,
290 .remove = __devexit_p(wl1251_spi_remove),
291};
292
293static int __init wl1251_spi_init(void)
294{
295 int ret;
296
297 ret = spi_register_driver(&wl1251_spi_driver);
298 if (ret < 0) {
299 wl1251_error("failed to register spi driver: %d", ret);
300 goto out;
301 }
302
303out:
304 return ret;
305}
306
307static void __exit wl1251_spi_exit(void)
308{
309 spi_unregister_driver(&wl1251_spi_driver);
310
311 wl1251_notice("unloaded");
312}
313
314module_init(wl1251_spi_init);
315module_exit(wl1251_spi_exit);
316
317MODULE_LICENSE("GPL");
318MODULE_AUTHOR("Kalle Valo <Kalle.Valo@nokia.com>");
319MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");