blob: 899cad34ccd3aa1649029d90294fe21c30608d14 [file] [log] [blame]
Solomon Peachya910e4a2013-05-24 20:04:38 -04001/*
2 * Mac80211 SPI driver for ST-Ericsson CW1200 device
3 *
4 * Copyright (c) 2011, Sagrad Inc.
5 * Author: Solomon Peachy <speachy@sagrad.com>
6 *
7 * Based on cw1200_sdio.c
8 * Copyright (c) 2010, ST-Ericsson
9 * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
14 */
15
Solomon Peachya910e4a2013-05-24 20:04:38 -040016#include <linux/module.h>
17#include <linux/gpio.h>
18#include <linux/delay.h>
19#include <linux/spinlock.h>
20#include <linux/interrupt.h>
21#include <net/mac80211.h>
22
23#include <linux/spi/spi.h>
24#include <linux/device.h>
25
26#include "cw1200.h"
Solomon Peachy911373c2013-06-01 08:08:42 -040027#include "hwbus.h"
Solomon Peachy4da2a54a2013-06-02 11:35:32 -040028#include <linux/platform_data/net-cw1200.h>
Solomon Peachya910e4a2013-05-24 20:04:38 -040029#include "hwio.h"
30
31MODULE_AUTHOR("Solomon Peachy <speachy@sagrad.com>");
32MODULE_DESCRIPTION("mac80211 ST-Ericsson CW1200 SPI driver");
33MODULE_LICENSE("GPL");
34MODULE_ALIAS("spi:cw1200_wlan_spi");
35
36/* #define SPI_DEBUG */
37
Solomon Peachy911373c2013-06-01 08:08:42 -040038struct hwbus_priv {
Solomon Peachya910e4a2013-05-24 20:04:38 -040039 struct spi_device *func;
40 struct cw1200_common *core;
41 const struct cw1200_platform_data_spi *pdata;
42 spinlock_t lock; /* Serialize all bus operations */
Solomon Peachy85ba8f52013-08-27 20:29:47 -040043 wait_queue_head_t wq;
Solomon Peachya910e4a2013-05-24 20:04:38 -040044 int claimed;
45};
46
47#define SDIO_TO_SPI_ADDR(addr) ((addr & 0x1f)>>2)
48#define SET_WRITE 0x7FFF /* usage: and operation */
49#define SET_READ 0x8000 /* usage: or operation */
50
Solomon Peachy8b3e7be2013-06-11 09:49:40 -040051/* Notes on byte ordering:
Solomon Peachya910e4a2013-05-24 20:04:38 -040052 LE: B0 B1 B2 B3
53 BE: B3 B2 B1 B0
54
55 Hardware expects 32-bit data to be written as 16-bit BE words:
56
57 B1 B0 B3 B2
Solomon Peachya910e4a2013-05-24 20:04:38 -040058*/
59
Solomon Peachy911373c2013-06-01 08:08:42 -040060static int cw1200_spi_memcpy_fromio(struct hwbus_priv *self,
Solomon Peachya910e4a2013-05-24 20:04:38 -040061 unsigned int addr,
62 void *dst, int count)
63{
64 int ret, i;
Solomon Peachy72584162013-06-20 23:03:12 -040065 u16 regaddr;
Solomon Peachya910e4a2013-05-24 20:04:38 -040066 struct spi_message m;
67
68 struct spi_transfer t_addr = {
69 .tx_buf = &regaddr,
70 .len = sizeof(regaddr),
71 };
72 struct spi_transfer t_msg = {
73 .rx_buf = dst,
74 .len = count,
75 };
76
77 regaddr = (SDIO_TO_SPI_ADDR(addr))<<12;
78 regaddr |= SET_READ;
79 regaddr |= (count>>1);
Solomon Peachya910e4a2013-05-24 20:04:38 -040080
81#ifdef SPI_DEBUG
Solomon Peachy72584162013-06-20 23:03:12 -040082 pr_info("READ : %04d from 0x%02x (%04x)\n", count, addr, regaddr);
Solomon Peachya910e4a2013-05-24 20:04:38 -040083#endif
84
Solomon Peachy72584162013-06-20 23:03:12 -040085 /* Header is LE16 */
86 regaddr = cpu_to_le16(regaddr);
87
88 /* We have to byteswap if the SPI bus is limited to 8b operation
89 or we are running on a Big Endian system
90 */
Solomon Peachya910e4a2013-05-24 20:04:38 -040091#if defined(__LITTLE_ENDIAN)
Solomon Peachya910e4a2013-05-24 20:04:38 -040092 if (self->func->bits_per_word == 8)
93#endif
94 regaddr = swab16(regaddr);
95
96 spi_message_init(&m);
97 spi_message_add_tail(&t_addr, &m);
98 spi_message_add_tail(&t_msg, &m);
99 ret = spi_sync(self->func, &m);
100
101#ifdef SPI_DEBUG
102 pr_info("READ : ");
103 for (i = 0; i < t_addr.len; i++)
104 printk("%02x ", ((u8 *)t_addr.tx_buf)[i]);
105 printk(" : ");
106 for (i = 0; i < t_msg.len; i++)
107 printk("%02x ", ((u8 *)t_msg.rx_buf)[i]);
108 printk("\n");
109#endif
110
Solomon Peachy72584162013-06-20 23:03:12 -0400111 /* We have to byteswap if the SPI bus is limited to 8b operation
112 or we are running on a Big Endian system
113 */
Solomon Peachya910e4a2013-05-24 20:04:38 -0400114#if defined(__LITTLE_ENDIAN)
Solomon Peachya910e4a2013-05-24 20:04:38 -0400115 if (self->func->bits_per_word == 8)
116#endif
117 {
118 uint16_t *buf = (uint16_t *)dst;
119 for (i = 0; i < ((count + 1) >> 1); i++)
120 buf[i] = swab16(buf[i]);
121 }
122
123 return ret;
124}
125
Solomon Peachy911373c2013-06-01 08:08:42 -0400126static int cw1200_spi_memcpy_toio(struct hwbus_priv *self,
Solomon Peachya910e4a2013-05-24 20:04:38 -0400127 unsigned int addr,
128 const void *src, int count)
129{
130 int rval, i;
Solomon Peachy72584162013-06-20 23:03:12 -0400131 u16 regaddr;
Solomon Peachya910e4a2013-05-24 20:04:38 -0400132 struct spi_transfer t_addr = {
133 .tx_buf = &regaddr,
134 .len = sizeof(regaddr),
135 };
136 struct spi_transfer t_msg = {
137 .tx_buf = src,
138 .len = count,
139 };
140 struct spi_message m;
141
142 regaddr = (SDIO_TO_SPI_ADDR(addr))<<12;
143 regaddr &= SET_WRITE;
144 regaddr |= (count>>1);
Solomon Peachya910e4a2013-05-24 20:04:38 -0400145
146#ifdef SPI_DEBUG
Solomon Peachy72584162013-06-20 23:03:12 -0400147 pr_info("WRITE: %04d to 0x%02x (%04x)\n", count, addr, regaddr);
Solomon Peachya910e4a2013-05-24 20:04:38 -0400148#endif
149
Solomon Peachy72584162013-06-20 23:03:12 -0400150 /* Header is LE16 */
151 regaddr = cpu_to_le16(regaddr);
152
153 /* We have to byteswap if the SPI bus is limited to 8b operation
154 or we are running on a Big Endian system
155 */
Solomon Peachya910e4a2013-05-24 20:04:38 -0400156#if defined(__LITTLE_ENDIAN)
Solomon Peachya910e4a2013-05-24 20:04:38 -0400157 if (self->func->bits_per_word == 8)
158#endif
159 {
160 uint16_t *buf = (uint16_t *)src;
Solomon Peachy72584162013-06-20 23:03:12 -0400161 regaddr = swab16(regaddr);
Solomon Peachya910e4a2013-05-24 20:04:38 -0400162 for (i = 0; i < ((count + 1) >> 1); i++)
163 buf[i] = swab16(buf[i]);
164 }
165
166#ifdef SPI_DEBUG
167 pr_info("WRITE: ");
168 for (i = 0; i < t_addr.len; i++)
169 printk("%02x ", ((u8 *)t_addr.tx_buf)[i]);
170 printk(" : ");
171 for (i = 0; i < t_msg.len; i++)
172 printk("%02x ", ((u8 *)t_msg.tx_buf)[i]);
173 printk("\n");
174#endif
175
176 spi_message_init(&m);
177 spi_message_add_tail(&t_addr, &m);
178 spi_message_add_tail(&t_msg, &m);
179 rval = spi_sync(self->func, &m);
180
181#ifdef SPI_DEBUG
182 pr_info("WROTE: %d\n", m.actual_length);
183#endif
184
185#if defined(__LITTLE_ENDIAN)
186 /* We have to byteswap if the SPI bus is limited to 8b operation */
187 if (self->func->bits_per_word == 8)
188#endif
189 {
190 uint16_t *buf = (uint16_t *)src;
191 for (i = 0; i < ((count + 1) >> 1); i++)
192 buf[i] = swab16(buf[i]);
193 }
194 return rval;
195}
196
Solomon Peachy911373c2013-06-01 08:08:42 -0400197static void cw1200_spi_lock(struct hwbus_priv *self)
Solomon Peachya910e4a2013-05-24 20:04:38 -0400198{
199 unsigned long flags;
200
Solomon Peachy85ba8f52013-08-27 20:29:47 -0400201 DECLARE_WAITQUEUE(wait, current);
202
Solomon Peachya910e4a2013-05-24 20:04:38 -0400203 might_sleep();
204
Solomon Peachy85ba8f52013-08-27 20:29:47 -0400205 add_wait_queue(&self->wq, &wait);
Solomon Peachya910e4a2013-05-24 20:04:38 -0400206 spin_lock_irqsave(&self->lock, flags);
207 while (1) {
208 set_current_state(TASK_UNINTERRUPTIBLE);
209 if (!self->claimed)
210 break;
211 spin_unlock_irqrestore(&self->lock, flags);
212 schedule();
213 spin_lock_irqsave(&self->lock, flags);
214 }
215 set_current_state(TASK_RUNNING);
216 self->claimed = 1;
217 spin_unlock_irqrestore(&self->lock, flags);
Solomon Peachy85ba8f52013-08-27 20:29:47 -0400218 remove_wait_queue(&self->wq, &wait);
Solomon Peachya910e4a2013-05-24 20:04:38 -0400219
220 return;
221}
222
Solomon Peachy911373c2013-06-01 08:08:42 -0400223static void cw1200_spi_unlock(struct hwbus_priv *self)
Solomon Peachya910e4a2013-05-24 20:04:38 -0400224{
225 unsigned long flags;
226
227 spin_lock_irqsave(&self->lock, flags);
228 self->claimed = 0;
229 spin_unlock_irqrestore(&self->lock, flags);
Solomon Peachy85ba8f52013-08-27 20:29:47 -0400230 wake_up(&self->wq);
231
Solomon Peachya910e4a2013-05-24 20:04:38 -0400232 return;
233}
234
235static irqreturn_t cw1200_spi_irq_handler(int irq, void *dev_id)
236{
Solomon Peachy911373c2013-06-01 08:08:42 -0400237 struct hwbus_priv *self = dev_id;
Solomon Peachya910e4a2013-05-24 20:04:38 -0400238
239 if (self->core) {
240 cw1200_irq_handler(self->core);
241 return IRQ_HANDLED;
242 } else {
243 return IRQ_NONE;
244 }
245}
246
Solomon Peachy911373c2013-06-01 08:08:42 -0400247static int cw1200_spi_irq_subscribe(struct hwbus_priv *self)
Solomon Peachya910e4a2013-05-24 20:04:38 -0400248{
249 int ret;
250
251 pr_debug("SW IRQ subscribe\n");
252
Solomon Peachy87421cb2013-09-23 16:00:04 -0400253 ret = request_threaded_irq(self->func->irq, NULL,
254 cw1200_spi_irq_handler,
255 IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
256 "cw1200_wlan_irq", self);
Solomon Peachya910e4a2013-05-24 20:04:38 -0400257 if (WARN_ON(ret < 0))
258 goto exit;
259
260 ret = enable_irq_wake(self->func->irq);
261 if (WARN_ON(ret))
262 goto free_irq;
263
264 return 0;
265
266free_irq:
267 free_irq(self->func->irq, self);
268exit:
269 return ret;
270}
271
Solomon Peachy911373c2013-06-01 08:08:42 -0400272static int cw1200_spi_irq_unsubscribe(struct hwbus_priv *self)
Solomon Peachya910e4a2013-05-24 20:04:38 -0400273{
Solomon Peachyc4fb19d2013-09-23 16:00:03 -0400274 int ret = 0;
275
Solomon Peachya910e4a2013-05-24 20:04:38 -0400276 pr_debug("SW IRQ unsubscribe\n");
277 disable_irq_wake(self->func->irq);
278 free_irq(self->func->irq, self);
279
Solomon Peachyc4fb19d2013-09-23 16:00:03 -0400280 return ret;
Solomon Peachya910e4a2013-05-24 20:04:38 -0400281}
282
283static int cw1200_spi_off(const struct cw1200_platform_data_spi *pdata)
284{
Solomon Peachy6dd64a32013-06-02 09:53:03 -0400285 if (pdata->reset) {
286 gpio_set_value(pdata->reset, 0);
Solomon Peachya910e4a2013-05-24 20:04:38 -0400287 msleep(30); /* Min is 2 * CLK32K cycles */
Solomon Peachy6dd64a32013-06-02 09:53:03 -0400288 gpio_free(pdata->reset);
Solomon Peachya910e4a2013-05-24 20:04:38 -0400289 }
290
291 if (pdata->power_ctrl)
292 pdata->power_ctrl(pdata, false);
293 if (pdata->clk_ctrl)
294 pdata->clk_ctrl(pdata, false);
295
296 return 0;
297}
298
299static int cw1200_spi_on(const struct cw1200_platform_data_spi *pdata)
300{
Solomon Peachya910e4a2013-05-24 20:04:38 -0400301 /* Ensure I/Os are pulled low */
Solomon Peachy6dd64a32013-06-02 09:53:03 -0400302 if (pdata->reset) {
303 gpio_request(pdata->reset, "cw1200_wlan_reset");
304 gpio_direction_output(pdata->reset, 0);
Solomon Peachya910e4a2013-05-24 20:04:38 -0400305 }
Solomon Peachy6dd64a32013-06-02 09:53:03 -0400306 if (pdata->powerup) {
307 gpio_request(pdata->powerup, "cw1200_wlan_powerup");
308 gpio_direction_output(pdata->powerup, 0);
Solomon Peachya910e4a2013-05-24 20:04:38 -0400309 }
Solomon Peachy6dd64a32013-06-02 09:53:03 -0400310 if (pdata->reset || pdata->powerup)
Solomon Peachya910e4a2013-05-24 20:04:38 -0400311 msleep(10); /* Settle time? */
312
313 /* Enable 3v3 and 1v8 to hardware */
314 if (pdata->power_ctrl) {
315 if (pdata->power_ctrl(pdata, true)) {
316 pr_err("power_ctrl() failed!\n");
317 return -1;
318 }
319 }
320
321 /* Enable CLK32K */
322 if (pdata->clk_ctrl) {
323 if (pdata->clk_ctrl(pdata, true)) {
324 pr_err("clk_ctrl() failed!\n");
325 return -1;
326 }
327 msleep(10); /* Delay until clock is stable for 2 cycles */
328 }
329
330 /* Enable POWERUP signal */
Solomon Peachy6dd64a32013-06-02 09:53:03 -0400331 if (pdata->powerup) {
332 gpio_set_value(pdata->powerup, 1);
Solomon Peachya910e4a2013-05-24 20:04:38 -0400333 msleep(250); /* or more..? */
334 }
335 /* Enable RSTn signal */
Solomon Peachy6dd64a32013-06-02 09:53:03 -0400336 if (pdata->reset) {
337 gpio_set_value(pdata->reset, 1);
Solomon Peachya910e4a2013-05-24 20:04:38 -0400338 msleep(50); /* Or more..? */
339 }
340 return 0;
341}
342
Solomon Peachy911373c2013-06-01 08:08:42 -0400343static size_t cw1200_spi_align_size(struct hwbus_priv *self, size_t size)
Solomon Peachya910e4a2013-05-24 20:04:38 -0400344{
345 return size & 1 ? size + 1 : size;
346}
347
Solomon Peachy911373c2013-06-01 08:08:42 -0400348static int cw1200_spi_pm(struct hwbus_priv *self, bool suspend)
Solomon Peachya910e4a2013-05-24 20:04:38 -0400349{
350 return irq_set_irq_wake(self->func->irq, suspend);
351}
352
Solomon Peachy911373c2013-06-01 08:08:42 -0400353static struct hwbus_ops cw1200_spi_hwbus_ops = {
354 .hwbus_memcpy_fromio = cw1200_spi_memcpy_fromio,
355 .hwbus_memcpy_toio = cw1200_spi_memcpy_toio,
Solomon Peachya910e4a2013-05-24 20:04:38 -0400356 .lock = cw1200_spi_lock,
357 .unlock = cw1200_spi_unlock,
358 .align_size = cw1200_spi_align_size,
359 .power_mgmt = cw1200_spi_pm,
360};
361
362/* Probe Function to be called by SPI stack when device is discovered */
363static int cw1200_spi_probe(struct spi_device *func)
364{
365 const struct cw1200_platform_data_spi *plat_data =
366 func->dev.platform_data;
Solomon Peachy911373c2013-06-01 08:08:42 -0400367 struct hwbus_priv *self;
Solomon Peachya910e4a2013-05-24 20:04:38 -0400368 int status;
369
370 /* Sanity check speed */
371 if (func->max_speed_hz > 52000000)
372 func->max_speed_hz = 52000000;
373 if (func->max_speed_hz < 1000000)
374 func->max_speed_hz = 1000000;
375
376 /* Fix up transfer size */
377 if (plat_data->spi_bits_per_word)
378 func->bits_per_word = plat_data->spi_bits_per_word;
379 if (!func->bits_per_word)
380 func->bits_per_word = 16;
381
382 /* And finally.. */
383 func->mode = SPI_MODE_0;
384
385 pr_info("cw1200_wlan_spi: Probe called (CS %d M %d BPW %d CLK %d)\n",
386 func->chip_select, func->mode, func->bits_per_word,
387 func->max_speed_hz);
388
389 if (cw1200_spi_on(plat_data)) {
390 pr_err("spi_on() failed!\n");
391 return -1;
392 }
393
394 if (spi_setup(func)) {
395 pr_err("spi_setup() failed!\n");
396 return -1;
397 }
398
399 self = kzalloc(sizeof(*self), GFP_KERNEL);
400 if (!self) {
Solomon Peachy911373c2013-06-01 08:08:42 -0400401 pr_err("Can't allocate SPI hwbus_priv.");
Solomon Peachya910e4a2013-05-24 20:04:38 -0400402 return -ENOMEM;
403 }
404
405 self->pdata = plat_data;
406 self->func = func;
407 spin_lock_init(&self->lock);
408
409 spi_set_drvdata(func, self);
410
Solomon Peachy85ba8f52013-08-27 20:29:47 -0400411 init_waitqueue_head(&self->wq);
412
Solomon Peachya910e4a2013-05-24 20:04:38 -0400413 status = cw1200_spi_irq_subscribe(self);
414
Solomon Peachy911373c2013-06-01 08:08:42 -0400415 status = cw1200_core_probe(&cw1200_spi_hwbus_ops,
Solomon Peachya910e4a2013-05-24 20:04:38 -0400416 self, &func->dev, &self->core,
417 self->pdata->ref_clk,
418 self->pdata->macaddr,
419 self->pdata->sdd_file,
420 self->pdata->have_5ghz);
421
422 if (status) {
423 cw1200_spi_irq_unsubscribe(self);
424 cw1200_spi_off(plat_data);
425 kfree(self);
426 }
427
428 return status;
429}
430
431/* Disconnect Function to be called by SPI stack when device is disconnected */
432static int cw1200_spi_disconnect(struct spi_device *func)
433{
Solomon Peachy911373c2013-06-01 08:08:42 -0400434 struct hwbus_priv *self = spi_get_drvdata(func);
Solomon Peachya910e4a2013-05-24 20:04:38 -0400435
436 if (self) {
437 cw1200_spi_irq_unsubscribe(self);
438 if (self->core) {
439 cw1200_core_release(self->core);
440 self->core = NULL;
441 }
442 kfree(self);
443 }
444 cw1200_spi_off(func->dev.platform_data);
445
446 return 0;
447}
448
Solomon Peachy4e17b872013-05-29 22:22:05 -0400449#ifdef CONFIG_PM
Solomon Peachya910e4a2013-05-24 20:04:38 -0400450static int cw1200_spi_suspend(struct device *dev, pm_message_t state)
451{
Solomon Peachy911373c2013-06-01 08:08:42 -0400452 struct hwbus_priv *self = spi_get_drvdata(to_spi_device(dev));
Solomon Peachya910e4a2013-05-24 20:04:38 -0400453
454 if (!cw1200_can_suspend(self->core))
455 return -EAGAIN;
456
457 /* XXX notify host that we have to keep CW1200 powered on? */
458 return 0;
459}
460
461static int cw1200_spi_resume(struct device *dev)
462{
463 return 0;
464}
Solomon Peachy4e17b872013-05-29 22:22:05 -0400465#endif
Solomon Peachya910e4a2013-05-24 20:04:38 -0400466
467static struct spi_driver spi_driver = {
468 .probe = cw1200_spi_probe,
469 .remove = cw1200_spi_disconnect,
470 .driver = {
471 .name = "cw1200_wlan_spi",
472 .bus = &spi_bus_type,
473 .owner = THIS_MODULE,
Solomon Peachy4e17b872013-05-29 22:22:05 -0400474#ifdef CONFIG_PM
Solomon Peachya910e4a2013-05-24 20:04:38 -0400475 .suspend = cw1200_spi_suspend,
476 .resume = cw1200_spi_resume,
Solomon Peachy4e17b872013-05-29 22:22:05 -0400477#endif
Solomon Peachya910e4a2013-05-24 20:04:38 -0400478 },
479};
480
Wei Yongjund071c042013-05-30 19:42:54 +0800481module_spi_driver(spi_driver);