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