blob: 2dd659886a04c27c7c2679faeabfed38c2c8a73e [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
4 * Copyright (C) 2008-2009 Nokia Corporation
5 *
6 * Contact: Luciano Coelho <luciano.coelho@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
Alexey Dobriyana6b7a402011-06-06 10:43:46 +000024#include <linux/interrupt.h>
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +020025#include <linux/irq.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030026#include <linux/module.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030027#include <linux/crc7.h>
28#include <linux/spi/spi.h>
Ohad Ben-Cohenc1f9a092010-09-16 13:16:02 +020029#include <linux/wl12xx.h>
Felipe Balbi0969d672011-10-05 09:29:13 +030030#include <linux/platform_device.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090031#include <linux/slab.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030032
Shahar Levi00d20102010-11-08 11:20:10 +000033#include "wl12xx.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030034#include "wl12xx_80211.h"
Shahar Levi00d20102010-11-08 11:20:10 +000035#include "io.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030036
Shahar Levi00d20102010-11-08 11:20:10 +000037#include "reg.h"
Teemu Paasikivi760d9692010-02-22 08:38:25 +020038
39#define WSPI_CMD_READ 0x40000000
40#define WSPI_CMD_WRITE 0x00000000
41#define WSPI_CMD_FIXED 0x20000000
42#define WSPI_CMD_BYTE_LENGTH 0x1FFE0000
43#define WSPI_CMD_BYTE_LENGTH_OFFSET 17
44#define WSPI_CMD_BYTE_ADDR 0x0001FFFF
45
46#define WSPI_INIT_CMD_CRC_LEN 5
47
48#define WSPI_INIT_CMD_START 0x00
49#define WSPI_INIT_CMD_TX 0x40
50/* the extra bypass bit is sampled by the TNET as '1' */
51#define WSPI_INIT_CMD_BYPASS_BIT 0x80
52#define WSPI_INIT_CMD_FIXEDBUSY_LEN 0x07
53#define WSPI_INIT_CMD_EN_FIXEDBUSY 0x80
54#define WSPI_INIT_CMD_DIS_FIXEDBUSY 0x00
55#define WSPI_INIT_CMD_IOD 0x40
56#define WSPI_INIT_CMD_IP 0x20
57#define WSPI_INIT_CMD_CS 0x10
58#define WSPI_INIT_CMD_WS 0x08
59#define WSPI_INIT_CMD_WSPI 0x01
60#define WSPI_INIT_CMD_END 0x01
61
62#define WSPI_INIT_CMD_LEN 8
63
64#define HW_ACCESS_WSPI_FIXED_BUSY_LEN \
65 ((WL1271_BUSY_WORD_LEN - 4) / sizeof(u32))
66#define HW_ACCESS_WSPI_INIT_CMD_MASK 0
67
Ido Yariv5c57a902010-09-30 13:28:26 +020068/* HW limitation: maximum possible chunk size is 4095 bytes */
69#define WSPI_MAX_CHUNK_SIZE 4092
70
71#define WSPI_MAX_NUM_OF_CHUNKS (WL1271_AGGR_BUFFER_SIZE / WSPI_MAX_CHUNK_SIZE)
72
Felipe Balbib65019f2011-10-04 23:36:47 +030073struct wl12xx_spi_glue {
74 struct device *dev;
75 struct wl1271 *wl;
Felipe Balbi0969d672011-10-05 09:29:13 +030076 struct platform_device *core;
Felipe Balbib65019f2011-10-04 23:36:47 +030077};
78
79static inline struct wl12xx_spi_glue *wl_to_glue(struct wl1271 *wl)
Teemu Paasikivi8197b712010-02-22 08:38:23 +020080{
81 return wl->if_priv;
82}
83
84static struct device *wl1271_spi_wl_to_dev(struct wl1271 *wl)
85{
Felipe Balbib65019f2011-10-04 23:36:47 +030086 return wl_to_glue(wl)->dev;
Teemu Paasikivi8197b712010-02-22 08:38:23 +020087}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030088
Teemu Paasikivi760d9692010-02-22 08:38:25 +020089static void wl1271_spi_disable_interrupts(struct wl1271 *wl)
Teemu Paasikivi54f7e502010-02-22 08:38:22 +020090{
91 disable_irq(wl->irq);
92}
93
Teemu Paasikivi760d9692010-02-22 08:38:25 +020094static void wl1271_spi_enable_interrupts(struct wl1271 *wl)
Teemu Paasikivi54f7e502010-02-22 08:38:22 +020095{
96 enable_irq(wl->irq);
97}
98
Teemu Paasikivi760d9692010-02-22 08:38:25 +020099static void wl1271_spi_reset(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300100{
Felipe Balbib65019f2011-10-04 23:36:47 +0300101 struct wl12xx_spi_glue *glue = wl_to_glue(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300102 u8 *cmd;
103 struct spi_transfer t;
104 struct spi_message m;
105
106 cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL);
107 if (!cmd) {
108 wl1271_error("could not allocate cmd for spi reset");
109 return;
110 }
111
112 memset(&t, 0, sizeof(t));
113 spi_message_init(&m);
114
115 memset(cmd, 0xff, WSPI_INIT_CMD_LEN);
116
117 t.tx_buf = cmd;
118 t.len = WSPI_INIT_CMD_LEN;
119 spi_message_add_tail(&t, &m);
120
Felipe Balbib65019f2011-10-04 23:36:47 +0300121 spi_sync(to_spi_device(glue->dev), &m);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300122
123 wl1271_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN);
Dan Carpenter0dd38662010-12-21 07:00:13 +0300124 kfree(cmd);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300125}
126
Teemu Paasikivi760d9692010-02-22 08:38:25 +0200127static void wl1271_spi_init(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300128{
Felipe Balbib65019f2011-10-04 23:36:47 +0300129 struct wl12xx_spi_glue *glue = wl_to_glue(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300130 u8 crc[WSPI_INIT_CMD_CRC_LEN], *cmd;
131 struct spi_transfer t;
132 struct spi_message m;
133
134 cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL);
135 if (!cmd) {
136 wl1271_error("could not allocate cmd for spi init");
137 return;
138 }
139
140 memset(crc, 0, sizeof(crc));
141 memset(&t, 0, sizeof(t));
142 spi_message_init(&m);
143
144 /*
145 * Set WSPI_INIT_COMMAND
146 * the data is being send from the MSB to LSB
147 */
148 cmd[2] = 0xff;
149 cmd[3] = 0xff;
150 cmd[1] = WSPI_INIT_CMD_START | WSPI_INIT_CMD_TX;
151 cmd[0] = 0;
152 cmd[7] = 0;
153 cmd[6] |= HW_ACCESS_WSPI_INIT_CMD_MASK << 3;
154 cmd[6] |= HW_ACCESS_WSPI_FIXED_BUSY_LEN & WSPI_INIT_CMD_FIXEDBUSY_LEN;
155
156 if (HW_ACCESS_WSPI_FIXED_BUSY_LEN == 0)
157 cmd[5] |= WSPI_INIT_CMD_DIS_FIXEDBUSY;
158 else
159 cmd[5] |= WSPI_INIT_CMD_EN_FIXEDBUSY;
160
161 cmd[5] |= WSPI_INIT_CMD_IOD | WSPI_INIT_CMD_IP | WSPI_INIT_CMD_CS
162 | WSPI_INIT_CMD_WSPI | WSPI_INIT_CMD_WS;
163
164 crc[0] = cmd[1];
165 crc[1] = cmd[0];
166 crc[2] = cmd[7];
167 crc[3] = cmd[6];
168 crc[4] = cmd[5];
169
170 cmd[4] |= crc7(0, crc, WSPI_INIT_CMD_CRC_LEN) << 1;
171 cmd[4] |= WSPI_INIT_CMD_END;
172
173 t.tx_buf = cmd;
174 t.len = WSPI_INIT_CMD_LEN;
175 spi_message_add_tail(&t, &m);
176
Felipe Balbib65019f2011-10-04 23:36:47 +0300177 spi_sync(to_spi_device(glue->dev), &m);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300178 wl1271_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN);
Kulikov Vasiliybb123612010-07-31 20:33:59 +0400179 kfree(cmd);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300180}
181
Juuso Oikarinen545f1da2009-10-08 21:56:23 +0300182#define WL1271_BUSY_WORD_TIMEOUT 1000
183
Juuso Oikarinen259da432010-03-26 12:53:18 +0200184static int wl1271_spi_read_busy(struct wl1271 *wl)
Juuso Oikarinen545f1da2009-10-08 21:56:23 +0300185{
Felipe Balbib65019f2011-10-04 23:36:47 +0300186 struct wl12xx_spi_glue *glue = wl_to_glue(wl);
Juuso Oikarinen545f1da2009-10-08 21:56:23 +0300187 struct spi_transfer t[1];
188 struct spi_message m;
189 u32 *busy_buf;
190 int num_busy_bytes = 0;
191
Juuso Oikarinen545f1da2009-10-08 21:56:23 +0300192 /*
193 * Read further busy words from SPI until a non-busy word is
194 * encountered, then read the data itself into the buffer.
195 */
Juuso Oikarinen545f1da2009-10-08 21:56:23 +0300196
197 num_busy_bytes = WL1271_BUSY_WORD_TIMEOUT;
198 busy_buf = wl->buffer_busyword;
199 while (num_busy_bytes) {
200 num_busy_bytes--;
201 spi_message_init(&m);
202 memset(t, 0, sizeof(t));
203 t[0].rx_buf = busy_buf;
204 t[0].len = sizeof(u32);
Juuso Oikarinen259da432010-03-26 12:53:18 +0200205 t[0].cs_change = true;
Juuso Oikarinen545f1da2009-10-08 21:56:23 +0300206 spi_message_add_tail(&t[0], &m);
Felipe Balbib65019f2011-10-04 23:36:47 +0300207 spi_sync(to_spi_device(glue->dev), &m);
Juuso Oikarinen545f1da2009-10-08 21:56:23 +0300208
Juuso Oikarinen259da432010-03-26 12:53:18 +0200209 if (*busy_buf & 0x1)
210 return 0;
Juuso Oikarinen545f1da2009-10-08 21:56:23 +0300211 }
212
213 /* The SPI bus is unresponsive, the read failed. */
Juuso Oikarinen545f1da2009-10-08 21:56:23 +0300214 wl1271_error("SPI read busy-word timeout!\n");
Juuso Oikarinen259da432010-03-26 12:53:18 +0200215 return -ETIMEDOUT;
Juuso Oikarinen545f1da2009-10-08 21:56:23 +0300216}
217
Teemu Paasikivi760d9692010-02-22 08:38:25 +0200218static void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf,
Juuso Oikarinen259da432010-03-26 12:53:18 +0200219 size_t len, bool fixed)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300220{
Felipe Balbib65019f2011-10-04 23:36:47 +0300221 struct wl12xx_spi_glue *glue = wl_to_glue(wl);
Ido Yariv5c57a902010-09-30 13:28:26 +0200222 struct spi_transfer t[2];
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300223 struct spi_message m;
Juuso Oikarinen545f1da2009-10-08 21:56:23 +0300224 u32 *busy_buf;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300225 u32 *cmd;
Ido Yariv5c57a902010-09-30 13:28:26 +0200226 u32 chunk_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300227
Ido Yariv5c57a902010-09-30 13:28:26 +0200228 while (len > 0) {
229 chunk_len = min((size_t)WSPI_MAX_CHUNK_SIZE, len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300230
Ido Yariv5c57a902010-09-30 13:28:26 +0200231 cmd = &wl->buffer_cmd;
232 busy_buf = wl->buffer_busyword;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300233
Ido Yariv5c57a902010-09-30 13:28:26 +0200234 *cmd = 0;
235 *cmd |= WSPI_CMD_READ;
236 *cmd |= (chunk_len << WSPI_CMD_BYTE_LENGTH_OFFSET) &
237 WSPI_CMD_BYTE_LENGTH;
238 *cmd |= addr & WSPI_CMD_BYTE_ADDR;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300239
Ido Yariv5c57a902010-09-30 13:28:26 +0200240 if (fixed)
241 *cmd |= WSPI_CMD_FIXED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300242
Ido Yariv5c57a902010-09-30 13:28:26 +0200243 spi_message_init(&m);
244 memset(t, 0, sizeof(t));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300245
Ido Yariv5c57a902010-09-30 13:28:26 +0200246 t[0].tx_buf = cmd;
247 t[0].len = 4;
248 t[0].cs_change = true;
249 spi_message_add_tail(&t[0], &m);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300250
Ido Yariv5c57a902010-09-30 13:28:26 +0200251 /* Busy and non busy words read */
252 t[1].rx_buf = busy_buf;
253 t[1].len = WL1271_BUSY_WORD_LEN;
254 t[1].cs_change = true;
255 spi_message_add_tail(&t[1], &m);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300256
Felipe Balbib65019f2011-10-04 23:36:47 +0300257 spi_sync(to_spi_device(glue->dev), &m);
Ido Yariv5c57a902010-09-30 13:28:26 +0200258
259 if (!(busy_buf[WL1271_BUSY_WORD_CNT - 1] & 0x1) &&
260 wl1271_spi_read_busy(wl)) {
261 memset(buf, 0, chunk_len);
262 return;
263 }
264
265 spi_message_init(&m);
266 memset(t, 0, sizeof(t));
267
268 t[0].rx_buf = buf;
269 t[0].len = chunk_len;
270 t[0].cs_change = true;
271 spi_message_add_tail(&t[0], &m);
272
Felipe Balbib65019f2011-10-04 23:36:47 +0300273 spi_sync(to_spi_device(glue->dev), &m);
Ido Yariv5c57a902010-09-30 13:28:26 +0200274
275 wl1271_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd));
276 wl1271_dump(DEBUG_SPI, "spi_read buf <- ", buf, chunk_len);
277
278 if (!fixed)
279 addr += chunk_len;
280 buf += chunk_len;
281 len -= chunk_len;
Juuso Oikarinen259da432010-03-26 12:53:18 +0200282 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300283}
284
Teemu Paasikivi760d9692010-02-22 08:38:25 +0200285static void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf,
Juuso Oikarinen74621412009-10-12 15:08:54 +0300286 size_t len, bool fixed)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300287{
Felipe Balbib65019f2011-10-04 23:36:47 +0300288 struct wl12xx_spi_glue *glue = wl_to_glue(wl);
Ido Yariv5c57a902010-09-30 13:28:26 +0200289 struct spi_transfer t[2 * WSPI_MAX_NUM_OF_CHUNKS];
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300290 struct spi_message m;
Ido Yariv5c57a902010-09-30 13:28:26 +0200291 u32 commands[WSPI_MAX_NUM_OF_CHUNKS];
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300292 u32 *cmd;
Ido Yariv5c57a902010-09-30 13:28:26 +0200293 u32 chunk_len;
294 int i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300295
Ido Yariv5c57a902010-09-30 13:28:26 +0200296 WARN_ON(len > WL1271_AGGR_BUFFER_SIZE);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300297
298 spi_message_init(&m);
299 memset(t, 0, sizeof(t));
300
Ido Yariv5c57a902010-09-30 13:28:26 +0200301 cmd = &commands[0];
302 i = 0;
303 while (len > 0) {
304 chunk_len = min((size_t)WSPI_MAX_CHUNK_SIZE, len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300305
Ido Yariv5c57a902010-09-30 13:28:26 +0200306 *cmd = 0;
307 *cmd |= WSPI_CMD_WRITE;
308 *cmd |= (chunk_len << WSPI_CMD_BYTE_LENGTH_OFFSET) &
309 WSPI_CMD_BYTE_LENGTH;
310 *cmd |= addr & WSPI_CMD_BYTE_ADDR;
311
312 if (fixed)
313 *cmd |= WSPI_CMD_FIXED;
314
315 t[i].tx_buf = cmd;
316 t[i].len = sizeof(*cmd);
317 spi_message_add_tail(&t[i++], &m);
318
319 t[i].tx_buf = buf;
320 t[i].len = chunk_len;
321 spi_message_add_tail(&t[i++], &m);
322
323 wl1271_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd));
324 wl1271_dump(DEBUG_SPI, "spi_write buf -> ", buf, chunk_len);
325
326 if (!fixed)
327 addr += chunk_len;
328 buf += chunk_len;
329 len -= chunk_len;
330 cmd++;
331 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300332
Felipe Balbib65019f2011-10-04 23:36:47 +0300333 spi_sync(to_spi_device(glue->dev), &m);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300334}
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +0200335
Ido Yariva6208652011-03-01 15:14:41 +0200336static irqreturn_t wl1271_hardirq(int irq, void *cookie)
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +0200337{
Ido Yariva6208652011-03-01 15:14:41 +0200338 struct wl1271 *wl = cookie;
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +0200339 unsigned long flags;
340
341 wl1271_debug(DEBUG_IRQ, "IRQ");
342
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +0200343 /* complete the ELP completion */
344 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva6208652011-03-01 15:14:41 +0200345 set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +0200346 if (wl->elp_compl) {
347 complete(wl->elp_compl);
348 wl->elp_compl = NULL;
349 }
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +0200350 spin_unlock_irqrestore(&wl->wl_lock, flags);
351
Ido Yariva6208652011-03-01 15:14:41 +0200352 return IRQ_WAKE_THREAD;
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +0200353}
354
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200355static int wl1271_spi_set_power(struct wl1271 *wl, bool enable)
Teemu Paasikivibecd5512010-03-18 12:26:27 +0200356{
357 if (wl->set_power)
358 wl->set_power(enable);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200359
360 return 0;
Teemu Paasikivibecd5512010-03-18 12:26:27 +0200361}
362
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200363static struct wl1271_if_operations spi_ops = {
364 .read = wl1271_spi_raw_read,
365 .write = wl1271_spi_raw_write,
366 .reset = wl1271_spi_reset,
367 .init = wl1271_spi_init,
Teemu Paasikivibecd5512010-03-18 12:26:27 +0200368 .power = wl1271_spi_set_power,
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200369 .dev = wl1271_spi_wl_to_dev,
370 .enable_irq = wl1271_spi_enable_interrupts,
Luciano Coelhoa81159e2011-03-14 14:05:13 +0200371 .disable_irq = wl1271_spi_disable_interrupts,
372 .set_block_size = NULL,
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200373};
374
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +0200375static int __devinit wl1271_probe(struct spi_device *spi)
376{
Felipe Balbib65019f2011-10-04 23:36:47 +0300377 struct wl12xx_spi_glue *glue;
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +0200378 struct wl12xx_platform_data *pdata;
379 struct ieee80211_hw *hw;
380 struct wl1271 *wl;
Felipe Balbi0969d672011-10-05 09:29:13 +0300381 struct resource res[1];
Ido Yariv341b7cd2011-03-31 10:07:01 +0200382 unsigned long irqflags;
Felipe Balbib65019f2011-10-04 23:36:47 +0300383 int ret = -ENOMEM;
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +0200384
385 pdata = spi->dev.platform_data;
386 if (!pdata) {
387 wl1271_error("no platform data");
388 return -ENODEV;
389 }
390
Felipe Balbib65019f2011-10-04 23:36:47 +0300391 glue = kzalloc(sizeof(*glue), GFP_KERNEL);
392 if (!glue) {
393 wl1271_error("can't allocate glue");
394 goto out;
395 }
396
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +0200397 hw = wl1271_alloc_hw();
Felipe Balbib65019f2011-10-04 23:36:47 +0300398 if (IS_ERR(hw)) {
399 ret = PTR_ERR(hw);
400 goto out_free_glue;
401 }
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +0200402
403 wl = hw->priv;
404
Felipe Balbib65019f2011-10-04 23:36:47 +0300405 glue->dev = &spi->dev;
406 glue->wl = wl;
407
408 spi_set_drvdata(spi, glue);
409 wl->if_priv = glue;
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200410
411 wl->if_ops = &spi_ops;
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +0200412
413 /* This is the only SPI value that we need to set here, the rest
414 * comes from the board-peripherals file */
415 spi->bits_per_word = 32;
416
417 ret = spi_setup(spi);
418 if (ret < 0) {
419 wl1271_error("spi_setup failed");
Felipe Balbib65019f2011-10-04 23:36:47 +0300420 goto out_free_hw;
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +0200421 }
422
423 wl->set_power = pdata->set_power;
424 if (!wl->set_power) {
425 wl1271_error("set power function missing in platform data");
426 ret = -ENODEV;
Felipe Balbib65019f2011-10-04 23:36:47 +0300427 goto out_free_hw;
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +0200428 }
429
Ohad Ben-Cohen15cea992010-09-16 01:31:51 +0200430 wl->ref_clock = pdata->board_ref_clock;
Shahar Levi5ea417a2011-03-06 16:32:11 +0200431 wl->tcxo_clock = pdata->board_tcxo_clock;
Ido Yariv341b7cd2011-03-31 10:07:01 +0200432 wl->platform_quirks = pdata->platform_quirks;
433
434 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
435 irqflags = IRQF_TRIGGER_RISING;
436 else
437 irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
Ohad Ben-Cohen15cea992010-09-16 01:31:51 +0200438
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +0200439 wl->irq = spi->irq;
440 if (wl->irq < 0) {
441 wl1271_error("irq missing in platform data");
442 ret = -ENODEV;
Felipe Balbib65019f2011-10-04 23:36:47 +0300443 goto out_free_hw;
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +0200444 }
445
Ido Yariva6208652011-03-01 15:14:41 +0200446 ret = request_threaded_irq(wl->irq, wl1271_hardirq, wl1271_irq,
Ido Yariv341b7cd2011-03-31 10:07:01 +0200447 irqflags,
Ido Yariva6208652011-03-01 15:14:41 +0200448 DRIVER_NAME, wl);
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +0200449 if (ret < 0) {
450 wl1271_error("request_irq() failed: %d", ret);
Felipe Balbib65019f2011-10-04 23:36:47 +0300451 goto out_free_hw;
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +0200452 }
453
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +0200454 disable_irq(wl->irq);
455
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +0200456 ret = wl1271_init_ieee80211(wl);
457 if (ret)
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200458 goto out_irq;
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +0200459
460 ret = wl1271_register_hw(wl);
461 if (ret)
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200462 goto out_irq;
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +0200463
Felipe Balbi0969d672011-10-05 09:29:13 +0300464 glue->core = platform_device_alloc("wl12xx-spi", -1);
465 if (!glue->core) {
466 wl1271_error("can't allocate platform_device");
467 ret = -ENOMEM;
468 goto out_unreg_hw;
469 }
470
471 glue->core->dev.parent = &spi->dev;
472
473 memset(res, 0x00, sizeof(res));
474
475 res[0].start = spi->irq;
476 res[0].flags = IORESOURCE_IRQ;
477 res[0].name = "irq";
478
479 ret = platform_device_add_resources(glue->core, res, ARRAY_SIZE(res));
480 if (ret) {
481 wl1271_error("can't add resources");
482 goto out_dev_put;
483 }
484
485 ret = platform_device_add_data(glue->core, pdata, sizeof(*pdata));
486 if (ret) {
487 wl1271_error("can't add platform data");
488 goto out_dev_put;
489 }
490
491 ret = platform_device_add(glue->core);
492 if (ret) {
493 wl1271_error("can't register platform device");
494 goto out_dev_put;
495 }
496
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +0200497 return 0;
498
Felipe Balbi0969d672011-10-05 09:29:13 +0300499out_dev_put:
500 platform_device_put(glue->core);
501
502out_unreg_hw:
503 wl1271_unregister_hw(wl);
504
Felipe Balbib65019f2011-10-04 23:36:47 +0300505out_irq:
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +0200506 free_irq(wl->irq, wl);
507
Felipe Balbib65019f2011-10-04 23:36:47 +0300508out_free_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +0200509 wl1271_free_hw(wl);
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +0200510
Felipe Balbib65019f2011-10-04 23:36:47 +0300511out_free_glue:
512 kfree(glue);
513out:
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +0200514 return ret;
515}
516
517static int __devexit wl1271_remove(struct spi_device *spi)
518{
Felipe Balbib65019f2011-10-04 23:36:47 +0300519 struct wl12xx_spi_glue *glue = spi_get_drvdata(spi);
520 struct wl1271 *wl = glue->wl;
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +0200521
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +0200522 wl1271_unregister_hw(wl);
Juuso Oikarinen4e23b112010-08-13 04:46:48 +0200523 free_irq(wl->irq, wl);
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +0200524 wl1271_free_hw(wl);
Felipe Balbi0969d672011-10-05 09:29:13 +0300525 platform_device_del(glue->core);
526 platform_device_put(glue->core);
Felipe Balbib65019f2011-10-04 23:36:47 +0300527 kfree(glue);
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +0200528
529 return 0;
530}
531
532
533static struct spi_driver wl1271_spi_driver = {
534 .driver = {
Luciano Coelho7fdd50d2010-03-26 12:53:10 +0200535 .name = "wl1271_spi",
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +0200536 .bus = &spi_bus_type,
537 .owner = THIS_MODULE,
538 },
539
540 .probe = wl1271_probe,
541 .remove = __devexit_p(wl1271_remove),
542};
543
544static int __init wl1271_init(void)
545{
Felipe Balbiba2274c2011-05-14 00:26:23 +0300546 return spi_register_driver(&wl1271_spi_driver);
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +0200547}
548
549static void __exit wl1271_exit(void)
550{
551 spi_unregister_driver(&wl1271_spi_driver);
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +0200552}
553
554module_init(wl1271_init);
555module_exit(wl1271_exit);
556
557MODULE_LICENSE("GPL");
Luciano Coelho5245e3a2011-03-30 21:31:39 +0300558MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +0200559MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
Arik Nemtsovc302b2c2011-08-17 10:45:48 +0300560MODULE_FIRMWARE(WL127X_FW_NAME);
Shahar Levi5aa42342011-03-06 16:32:07 +0200561MODULE_FIRMWARE(WL128X_FW_NAME);
Ameya Palandef148cfd2010-07-05 17:12:38 +0300562MODULE_ALIAS("spi:wl1271");