| Kalle Valo | 2f01a1f | 2009-04-29 23:33:31 +0300 | [diff] [blame] | 1 | /* | 
| Kalle Valo | 80301cd | 2009-06-12 14:17:39 +0300 | [diff] [blame] | 2 |  * This file is part of wl1251 | 
| Kalle Valo | 2f01a1f | 2009-04-29 23:33:31 +0300 | [diff] [blame] | 3 |  * | 
 | 4 |  * Copyright (C) 2008 Nokia Corporation | 
 | 5 |  * | 
| Kalle Valo | 2f01a1f | 2009-04-29 23:33:31 +0300 | [diff] [blame] | 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 |  | 
| Alexey Dobriyan | a6b7a40 | 2011-06-06 10:43:46 +0000 | [diff] [blame] | 22 | #include <linux/interrupt.h> | 
| Bob Copeland | 8e639c0 | 2009-08-07 13:33:26 +0300 | [diff] [blame] | 23 | #include <linux/irq.h> | 
| Kalle Valo | 2f01a1f | 2009-04-29 23:33:31 +0300 | [diff] [blame] | 24 | #include <linux/module.h> | 
| Tejun Heo | 5a0e3ad | 2010-03-24 17:04:11 +0900 | [diff] [blame] | 25 | #include <linux/slab.h> | 
| Kalle Valo | 2f01a1f | 2009-04-29 23:33:31 +0300 | [diff] [blame] | 26 | #include <linux/crc7.h> | 
 | 27 | #include <linux/spi/spi.h> | 
| Ohad Ben-Cohen | c1f9a09 | 2010-09-16 13:16:02 +0200 | [diff] [blame] | 28 | #include <linux/wl12xx.h> | 
| Kalle Valo | 2f01a1f | 2009-04-29 23:33:31 +0300 | [diff] [blame] | 29 |  | 
| Kalle Valo | 1367411 | 2009-06-12 14:17:25 +0300 | [diff] [blame] | 30 | #include "wl1251.h" | 
| Kalle Valo | 9bc6772 | 2010-10-10 11:28:32 +0300 | [diff] [blame] | 31 | #include "reg.h" | 
 | 32 | #include "spi.h" | 
| Kalle Valo | 2f01a1f | 2009-04-29 23:33:31 +0300 | [diff] [blame] | 33 |  | 
| Bob Copeland | b5ed9c1 | 2009-08-07 13:33:49 +0300 | [diff] [blame] | 34 | static 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 |  | 
| Kalle Valo | 16e711f | 2009-08-07 13:35:04 +0300 | [diff] [blame] | 42 | 	ieee80211_queue_work(wl->hw, &wl->irq_work); | 
| Bob Copeland | b5ed9c1 | 2009-08-07 13:33:49 +0300 | [diff] [blame] | 43 |  | 
 | 44 | 	return IRQ_HANDLED; | 
 | 45 | } | 
 | 46 |  | 
| Bob Copeland | af8c78e | 2009-08-07 13:33:34 +0300 | [diff] [blame] | 47 | static struct spi_device *wl_to_spi(struct wl1251 *wl) | 
 | 48 | { | 
 | 49 | 	return wl->if_priv; | 
 | 50 | } | 
 | 51 |  | 
| Bob Copeland | 08d9f57 | 2009-08-07 13:33:11 +0300 | [diff] [blame] | 52 | static void wl1251_spi_reset(struct wl1251 *wl) | 
| Kalle Valo | 2f01a1f | 2009-04-29 23:33:31 +0300 | [diff] [blame] | 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) { | 
| Kalle Valo | 80301cd | 2009-06-12 14:17:39 +0300 | [diff] [blame] | 60 | 		wl1251_error("could not allocate cmd for spi reset"); | 
| Kalle Valo | 2f01a1f | 2009-04-29 23:33:31 +0300 | [diff] [blame] | 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 |  | 
| Bob Copeland | af8c78e | 2009-08-07 13:33:34 +0300 | [diff] [blame] | 73 | 	spi_sync(wl_to_spi(wl), &m); | 
| Kalle Valo | 2f01a1f | 2009-04-29 23:33:31 +0300 | [diff] [blame] | 74 |  | 
| Kalle Valo | 80301cd | 2009-06-12 14:17:39 +0300 | [diff] [blame] | 75 | 	wl1251_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN); | 
| Kalle Valo | 2f01a1f | 2009-04-29 23:33:31 +0300 | [diff] [blame] | 76 | } | 
 | 77 |  | 
| Bob Copeland | 8e639c0 | 2009-08-07 13:33:26 +0300 | [diff] [blame] | 78 | static void wl1251_spi_wake(struct wl1251 *wl) | 
| Kalle Valo | 2f01a1f | 2009-04-29 23:33:31 +0300 | [diff] [blame] | 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) { | 
| Kalle Valo | 80301cd | 2009-06-12 14:17:39 +0300 | [diff] [blame] | 86 | 		wl1251_error("could not allocate cmd for spi init"); | 
| Kalle Valo | 2f01a1f | 2009-04-29 23:33:31 +0300 | [diff] [blame] | 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 |  | 
| Bob Copeland | af8c78e | 2009-08-07 13:33:34 +0300 | [diff] [blame] | 127 | 	spi_sync(wl_to_spi(wl), &m); | 
| Kalle Valo | 2f01a1f | 2009-04-29 23:33:31 +0300 | [diff] [blame] | 128 |  | 
| Kalle Valo | 80301cd | 2009-06-12 14:17:39 +0300 | [diff] [blame] | 129 | 	wl1251_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN); | 
| Kalle Valo | 2f01a1f | 2009-04-29 23:33:31 +0300 | [diff] [blame] | 130 | } | 
 | 131 |  | 
| Bob Copeland | 08d9f57 | 2009-08-07 13:33:11 +0300 | [diff] [blame] | 132 | static void wl1251_spi_reset_wake(struct wl1251 *wl) | 
 | 133 | { | 
 | 134 | 	wl1251_spi_reset(wl); | 
| Bob Copeland | 8e639c0 | 2009-08-07 13:33:26 +0300 | [diff] [blame] | 135 | 	wl1251_spi_wake(wl); | 
| Bob Copeland | 08d9f57 | 2009-08-07 13:33:11 +0300 | [diff] [blame] | 136 | } | 
 | 137 |  | 
| Bob Copeland | 08d9f57 | 2009-08-07 13:33:11 +0300 | [diff] [blame] | 138 | static void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, | 
 | 139 | 			    size_t len) | 
| Kalle Valo | 2f01a1f | 2009-04-29 23:33:31 +0300 | [diff] [blame] | 140 | { | 
 | 141 | 	struct spi_transfer t[3]; | 
 | 142 | 	struct spi_message m; | 
| Kalle Valo | 5262c12 | 2009-06-12 14:14:55 +0300 | [diff] [blame] | 143 | 	u8 *busy_buf; | 
| Kalle Valo | 56343a3 | 2009-06-12 14:14:47 +0300 | [diff] [blame] | 144 | 	u32 *cmd; | 
| Kalle Valo | 2f01a1f | 2009-04-29 23:33:31 +0300 | [diff] [blame] | 145 |  | 
| Kalle Valo | 56343a3 | 2009-06-12 14:14:47 +0300 | [diff] [blame] | 146 | 	cmd = &wl->buffer_cmd; | 
| Kalle Valo | 5262c12 | 2009-06-12 14:14:55 +0300 | [diff] [blame] | 147 | 	busy_buf = wl->buffer_busyword; | 
| Kalle Valo | 56343a3 | 2009-06-12 14:14:47 +0300 | [diff] [blame] | 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; | 
| Kalle Valo | 2f01a1f | 2009-04-29 23:33:31 +0300 | [diff] [blame] | 153 |  | 
 | 154 | 	spi_message_init(&m); | 
 | 155 | 	memset(t, 0, sizeof(t)); | 
 | 156 |  | 
| Kalle Valo | 56343a3 | 2009-06-12 14:14:47 +0300 | [diff] [blame] | 157 | 	t[0].tx_buf = cmd; | 
| Kalle Valo | 2f01a1f | 2009-04-29 23:33:31 +0300 | [diff] [blame] | 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; | 
| Kalle Valo | 80301cd | 2009-06-12 14:17:39 +0300 | [diff] [blame] | 163 | 	t[1].len = WL1251_BUSY_WORD_LEN; | 
| Kalle Valo | 2f01a1f | 2009-04-29 23:33:31 +0300 | [diff] [blame] | 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 |  | 
| Bob Copeland | af8c78e | 2009-08-07 13:33:34 +0300 | [diff] [blame] | 170 | 	spi_sync(wl_to_spi(wl), &m); | 
| Kalle Valo | 2f01a1f | 2009-04-29 23:33:31 +0300 | [diff] [blame] | 171 |  | 
 | 172 | 	/* FIXME: check busy words */ | 
 | 173 |  | 
| Kalle Valo | 80301cd | 2009-06-12 14:17:39 +0300 | [diff] [blame] | 174 | 	wl1251_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd)); | 
 | 175 | 	wl1251_dump(DEBUG_SPI, "spi_read buf <- ", buf, len); | 
| Kalle Valo | 2f01a1f | 2009-04-29 23:33:31 +0300 | [diff] [blame] | 176 | } | 
 | 177 |  | 
| Bob Copeland | 08d9f57 | 2009-08-07 13:33:11 +0300 | [diff] [blame] | 178 | static void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf, | 
 | 179 | 			     size_t len) | 
| Kalle Valo | 2f01a1f | 2009-04-29 23:33:31 +0300 | [diff] [blame] | 180 | { | 
 | 181 | 	struct spi_transfer t[2]; | 
 | 182 | 	struct spi_message m; | 
| Kalle Valo | 56343a3 | 2009-06-12 14:14:47 +0300 | [diff] [blame] | 183 | 	u32 *cmd; | 
| Kalle Valo | 2f01a1f | 2009-04-29 23:33:31 +0300 | [diff] [blame] | 184 |  | 
| Kalle Valo | 56343a3 | 2009-06-12 14:14:47 +0300 | [diff] [blame] | 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; | 
| Kalle Valo | 2f01a1f | 2009-04-29 23:33:31 +0300 | [diff] [blame] | 191 |  | 
 | 192 | 	spi_message_init(&m); | 
 | 193 | 	memset(t, 0, sizeof(t)); | 
 | 194 |  | 
| Kalle Valo | 56343a3 | 2009-06-12 14:14:47 +0300 | [diff] [blame] | 195 | 	t[0].tx_buf = cmd; | 
 | 196 | 	t[0].len = sizeof(*cmd); | 
| Kalle Valo | 2f01a1f | 2009-04-29 23:33:31 +0300 | [diff] [blame] | 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 |  | 
| Bob Copeland | af8c78e | 2009-08-07 13:33:34 +0300 | [diff] [blame] | 203 | 	spi_sync(wl_to_spi(wl), &m); | 
| Kalle Valo | 2f01a1f | 2009-04-29 23:33:31 +0300 | [diff] [blame] | 204 |  | 
| Kalle Valo | 80301cd | 2009-06-12 14:17:39 +0300 | [diff] [blame] | 205 | 	wl1251_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd)); | 
 | 206 | 	wl1251_dump(DEBUG_SPI, "spi_write buf -> ", buf, len); | 
| Kalle Valo | 2f01a1f | 2009-04-29 23:33:31 +0300 | [diff] [blame] | 207 | } | 
| Bob Copeland | 08d9f57 | 2009-08-07 13:33:11 +0300 | [diff] [blame] | 208 |  | 
| Bob Copeland | b5ed9c1 | 2009-08-07 13:33:49 +0300 | [diff] [blame] | 209 | static void wl1251_spi_enable_irq(struct wl1251 *wl) | 
 | 210 | { | 
 | 211 | 	return enable_irq(wl->irq); | 
 | 212 | } | 
 | 213 |  | 
 | 214 | static void wl1251_spi_disable_irq(struct wl1251 *wl) | 
 | 215 | { | 
 | 216 | 	return disable_irq(wl->irq); | 
 | 217 | } | 
 | 218 |  | 
| Grazvydas Ignotas | cb7bbc7 | 2010-11-04 00:13:47 +0200 | [diff] [blame] | 219 | static 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 |  | 
| Bob Copeland | af8c78e | 2009-08-07 13:33:34 +0300 | [diff] [blame] | 227 | static const struct wl1251_if_operations wl1251_spi_ops = { | 
| Bob Copeland | 08d9f57 | 2009-08-07 13:33:11 +0300 | [diff] [blame] | 228 | 	.read = wl1251_spi_read, | 
 | 229 | 	.write = wl1251_spi_write, | 
 | 230 | 	.reset = wl1251_spi_reset_wake, | 
| Bob Copeland | b5ed9c1 | 2009-08-07 13:33:49 +0300 | [diff] [blame] | 231 | 	.enable_irq = wl1251_spi_enable_irq, | 
 | 232 | 	.disable_irq = wl1251_spi_disable_irq, | 
| Grazvydas Ignotas | cb7bbc7 | 2010-11-04 00:13:47 +0200 | [diff] [blame] | 233 | 	.power = wl1251_spi_set_power, | 
| Bob Copeland | 08d9f57 | 2009-08-07 13:33:11 +0300 | [diff] [blame] | 234 | }; | 
| Bob Copeland | 8e639c0 | 2009-08-07 13:33:26 +0300 | [diff] [blame] | 235 |  | 
 | 236 | static 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); | 
| Bob Copeland | af8c78e | 2009-08-07 13:33:34 +0300 | [diff] [blame] | 257 | 	wl->if_priv = spi; | 
| Bob Copeland | 8e639c0 | 2009-08-07 13:33:26 +0300 | [diff] [blame] | 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 |  | 
| David-John Willis | c95cf3d0 | 2009-11-17 18:50:09 +0200 | [diff] [blame] | 282 | 	wl->use_eeprom = pdata->use_eeprom; | 
 | 283 |  | 
| Bob Copeland | 8e639c0 | 2009-08-07 13:33:26 +0300 | [diff] [blame] | 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 |  | 
| Thomas Gleixner | dced35a | 2011-03-28 17:49:12 +0200 | [diff] [blame] | 290 | 	irq_set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); | 
| Bob Copeland | 8e639c0 | 2009-08-07 13:33:26 +0300 | [diff] [blame] | 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 |  | 
 | 309 | static int __devexit wl1251_spi_remove(struct spi_device *spi) | 
 | 310 | { | 
 | 311 | 	struct wl1251 *wl = dev_get_drvdata(&spi->dev); | 
 | 312 |  | 
| Bob Copeland | b5ed9c1 | 2009-08-07 13:33:49 +0300 | [diff] [blame] | 313 | 	free_irq(wl->irq, wl); | 
| Bob Copeland | 8e639c0 | 2009-08-07 13:33:26 +0300 | [diff] [blame] | 314 | 	wl1251_free_hw(wl); | 
 | 315 |  | 
 | 316 | 	return 0; | 
 | 317 | } | 
 | 318 |  | 
 | 319 | static struct spi_driver wl1251_spi_driver = { | 
 | 320 | 	.driver = { | 
| Kalle Valo | 7590a55 | 2010-04-02 15:31:46 +0300 | [diff] [blame] | 321 | 		.name		= DRIVER_NAME, | 
| Bob Copeland | 8e639c0 | 2009-08-07 13:33:26 +0300 | [diff] [blame] | 322 | 		.bus		= &spi_bus_type, | 
 | 323 | 		.owner		= THIS_MODULE, | 
 | 324 | 	}, | 
 | 325 |  | 
 | 326 | 	.probe		= wl1251_spi_probe, | 
 | 327 | 	.remove		= __devexit_p(wl1251_spi_remove), | 
 | 328 | }; | 
 | 329 |  | 
 | 330 | static int __init wl1251_spi_init(void) | 
 | 331 | { | 
 | 332 | 	int ret; | 
 | 333 |  | 
 | 334 | 	ret = spi_register_driver(&wl1251_spi_driver); | 
 | 335 | 	if (ret < 0) { | 
 | 336 | 		wl1251_error("failed to register spi driver: %d", ret); | 
 | 337 | 		goto out; | 
 | 338 | 	} | 
 | 339 |  | 
 | 340 | out: | 
 | 341 | 	return ret; | 
 | 342 | } | 
 | 343 |  | 
 | 344 | static void __exit wl1251_spi_exit(void) | 
 | 345 | { | 
 | 346 | 	spi_unregister_driver(&wl1251_spi_driver); | 
 | 347 |  | 
 | 348 | 	wl1251_notice("unloaded"); | 
 | 349 | } | 
 | 350 |  | 
 | 351 | module_init(wl1251_spi_init); | 
 | 352 | module_exit(wl1251_spi_exit); | 
 | 353 |  | 
 | 354 | MODULE_LICENSE("GPL"); | 
| Kalle Valo | 31c726f | 2010-08-22 22:46:15 +0300 | [diff] [blame] | 355 | MODULE_AUTHOR("Kalle Valo <kvalo@adurom.com>"); | 
| Ameya Palande | f148cfd | 2010-07-05 17:12:38 +0300 | [diff] [blame] | 356 | MODULE_ALIAS("spi:wl1251"); |