Commit | Line | Data |
---|---|---|
c5c77ba1 JK |
1 | #include <linux/module.h> |
2 | #include <linux/init.h> | |
3 | #include <linux/kernel.h> | |
4 | #include <linux/fs.h> | |
5 | #include <linux/slab.h> | |
6 | #include <linux/types.h> | |
7 | #include <linux/cdev.h> | |
7f9eb1fb | 8 | #include <linux/uaccess.h> |
c5c77ba1 JK |
9 | #include <linux/device.h> |
10 | #include <linux/spi/spi.h> | |
11 | ||
12 | #include "linux_wlan_common.h" | |
13 | ||
14 | #define USE_SPI_DMA 0 /* johnny add */ | |
15 | ||
16 | #ifdef WILC_ASIC_A0 | |
17 | #if defined(PLAT_PANDA_ES_OMAP4460) | |
18 | #define MIN_SPEED 12000000 | |
19 | #define MAX_SPEED 24000000 | |
20 | #elif defined(PLAT_WMS8304) | |
21 | #define MIN_SPEED 12000000 | |
22 | #define MAX_SPEED 24000000 /* 4000000 */ | |
23 | #elif defined(CUSTOMER_PLATFORM) | |
24 | /* | |
25 | TODO : define Clock speed under 48M. | |
26 | * | |
27 | * ex) | |
28 | * #define MIN_SPEED 24000000 | |
29 | * #define MAX_SPEED 48000000 | |
30 | */ | |
31 | #else | |
32 | #define MIN_SPEED 24000000 | |
33 | #define MAX_SPEED 48000000 | |
34 | #endif | |
35 | #else /* WILC_ASIC_A0 */ | |
36 | /* Limit clk to 6MHz on FPGA. */ | |
37 | #define MIN_SPEED 6000000 | |
38 | #define MAX_SPEED 6000000 | |
39 | #endif /* WILC_ASIC_A0 */ | |
40 | ||
41 | static uint32_t SPEED = MIN_SPEED; | |
42 | ||
43 | struct spi_device *wilc_spi_dev; | |
44 | void linux_spi_deinit(void *vp); | |
45 | ||
46 | static int __init wilc_bus_probe(struct spi_device *spi) | |
47 | { | |
48 | ||
49 | PRINT_D(BUS_DBG, "spiModalias: %s\n", spi->modalias); | |
50 | PRINT_D(BUS_DBG, "spiMax-Speed: %d\n", spi->max_speed_hz); | |
51 | wilc_spi_dev = spi; | |
52 | ||
53 | printk("Driver Initializing success\n"); | |
54 | return 0; | |
55 | } | |
56 | ||
57 | static int __exit wilc_bus_remove(struct spi_device *spi) | |
58 | { | |
59 | ||
c5c77ba1 JK |
60 | return 0; |
61 | } | |
62 | ||
63 | #ifdef CONFIG_OF | |
64 | static const struct of_device_id wilc1000_of_match[] = { | |
65 | { .compatible = "atmel,wilc_spi", }, | |
66 | {} | |
67 | }; | |
68 | MODULE_DEVICE_TABLE(of, wilc1000_of_match); | |
69 | #endif | |
70 | ||
71 | struct spi_driver wilc_bus __refdata = { | |
72 | .driver = { | |
73 | .name = MODALIAS, | |
74 | #ifdef CONFIG_OF | |
75 | .of_match_table = wilc1000_of_match, | |
76 | #endif | |
77 | }, | |
78 | .probe = wilc_bus_probe, | |
79 | .remove = __exit_p(wilc_bus_remove), | |
80 | }; | |
81 | ||
82 | ||
83 | void linux_spi_deinit(void *vp) | |
84 | { | |
85 | ||
86 | spi_unregister_driver(&wilc_bus); | |
87 | ||
88 | SPEED = MIN_SPEED; | |
89 | PRINT_ER("@@@@@@@@@@@@ restore SPI speed to %d @@@@@@@@@\n", SPEED); | |
90 | ||
91 | } | |
92 | ||
93 | ||
94 | ||
95 | int linux_spi_init(void *vp) | |
96 | { | |
97 | int ret = 1; | |
98 | static int called; | |
99 | ||
100 | ||
101 | if (called == 0) { | |
102 | called++; | |
c5c77ba1 JK |
103 | ret = spi_register_driver(&wilc_bus); |
104 | } | |
105 | ||
106 | /* change return value to match WILC interface */ | |
107 | (ret < 0) ? (ret = 0) : (ret = 1); | |
108 | ||
109 | return ret; | |
110 | } | |
111 | ||
112 | #if defined(PLAT_WMS8304) | |
113 | #define TXRX_PHASE_SIZE (4096) | |
114 | #endif | |
115 | ||
e89419bc | 116 | #if defined(TXRX_PHASE_SIZE) |
c5c77ba1 | 117 | |
51e825f7 | 118 | int linux_spi_write(u8 *b, uint32_t len) |
c5c77ba1 JK |
119 | { |
120 | int ret; | |
8dfaafd6 | 121 | |
c5c77ba1 JK |
122 | if (len > 0 && b != NULL) { |
123 | int i = 0; | |
124 | int blk = len / TXRX_PHASE_SIZE; | |
125 | int remainder = len % TXRX_PHASE_SIZE; | |
126 | ||
37bc15d8 | 127 | char *r_buffer = kzalloc(TXRX_PHASE_SIZE, GFP_KERNEL); |
8dfaafd6 | 128 | |
c5c77ba1 JK |
129 | if (!r_buffer) { |
130 | PRINT_ER("Failed to allocate memory for r_buffer\n"); | |
131 | } | |
132 | ||
133 | if (blk) { | |
134 | while (i < blk) { | |
135 | struct spi_message msg; | |
136 | struct spi_transfer tr = { | |
137 | .tx_buf = b + (i * TXRX_PHASE_SIZE), | |
c5c77ba1 JK |
138 | .len = TXRX_PHASE_SIZE, |
139 | .speed_hz = SPEED, | |
140 | .bits_per_word = 8, | |
141 | .delay_usecs = 0, | |
142 | }; | |
4d77c6cc | 143 | |
c5c77ba1 JK |
144 | tr.rx_buf = r_buffer; |
145 | ||
146 | memset(&msg, 0, sizeof(msg)); | |
147 | spi_message_init(&msg); | |
148 | msg.spi = wilc_spi_dev; | |
149 | msg.is_dma_mapped = USE_SPI_DMA; | |
150 | ||
151 | spi_message_add_tail(&tr, &msg); | |
152 | ret = spi_sync(wilc_spi_dev, &msg); | |
153 | if (ret < 0) { | |
154 | PRINT_ER("SPI transaction failed\n"); | |
155 | } | |
c5c77ba1 JK |
156 | i++; |
157 | ||
158 | } | |
159 | } | |
160 | if (remainder) { | |
161 | struct spi_message msg; | |
162 | struct spi_transfer tr = { | |
163 | .tx_buf = b + (blk * TXRX_PHASE_SIZE), | |
c5c77ba1 JK |
164 | .len = remainder, |
165 | .speed_hz = SPEED, | |
166 | .bits_per_word = 8, | |
167 | .delay_usecs = 0, | |
168 | }; | |
c5c77ba1 JK |
169 | tr.rx_buf = r_buffer; |
170 | ||
171 | memset(&msg, 0, sizeof(msg)); | |
172 | spi_message_init(&msg); | |
173 | msg.spi = wilc_spi_dev; | |
174 | msg.is_dma_mapped = USE_SPI_DMA; /* rachel */ | |
175 | ||
176 | spi_message_add_tail(&tr, &msg); | |
177 | ret = spi_sync(wilc_spi_dev, &msg); | |
178 | if (ret < 0) { | |
179 | PRINT_ER("SPI transaction failed\n"); | |
180 | } | |
181 | } | |
0256b540 | 182 | kfree(r_buffer); |
c5c77ba1 JK |
183 | } else { |
184 | PRINT_ER("can't write data with the following length: %d\n", len); | |
185 | PRINT_ER("FAILED due to NULL buffer or ZERO length check the following length: %d\n", len); | |
186 | ret = -1; | |
187 | } | |
188 | ||
189 | /* change return value to match WILC interface */ | |
190 | (ret < 0) ? (ret = 0) : (ret = 1); | |
191 | ||
192 | return ret; | |
193 | ||
194 | } | |
195 | ||
196 | #else | |
51e825f7 | 197 | int linux_spi_write(u8 *b, uint32_t len) |
c5c77ba1 JK |
198 | { |
199 | ||
200 | int ret; | |
201 | struct spi_message msg; | |
202 | ||
203 | if (len > 0 && b != NULL) { | |
204 | struct spi_transfer tr = { | |
205 | .tx_buf = b, | |
c5c77ba1 JK |
206 | .len = len, |
207 | .speed_hz = SPEED, | |
208 | .delay_usecs = 0, | |
209 | }; | |
37bc15d8 | 210 | char *r_buffer = kzalloc(len, GFP_KERNEL); |
8dfaafd6 | 211 | |
c5c77ba1 JK |
212 | if (!r_buffer) { |
213 | PRINT_ER("Failed to allocate memory for r_buffer\n"); | |
214 | } | |
215 | tr.rx_buf = r_buffer; | |
216 | PRINT_D(BUS_DBG, "Request writing %d bytes\n", len); | |
217 | ||
218 | memset(&msg, 0, sizeof(msg)); | |
219 | spi_message_init(&msg); | |
220 | /* [[johnny add */ | |
221 | msg.spi = wilc_spi_dev; | |
222 | msg.is_dma_mapped = USE_SPI_DMA; | |
223 | /* ]] */ | |
224 | spi_message_add_tail(&tr, &msg); | |
225 | ||
226 | ret = spi_sync(wilc_spi_dev, &msg); | |
227 | if (ret < 0) { | |
228 | PRINT_ER("SPI transaction failed\n"); | |
229 | } | |
230 | ||
231 | kfree(r_buffer); | |
232 | } else { | |
233 | PRINT_ER("can't write data with the following length: %d\n", len); | |
234 | PRINT_ER("FAILED due to NULL buffer or ZERO length check the following length: %d\n", len); | |
235 | ret = -1; | |
236 | } | |
237 | ||
238 | /* change return value to match WILC interface */ | |
239 | (ret < 0) ? (ret = 0) : (ret = 1); | |
240 | ||
241 | ||
242 | return ret; | |
243 | } | |
244 | ||
245 | #endif | |
246 | ||
e89419bc | 247 | #if defined(TXRX_PHASE_SIZE) |
c5c77ba1 JK |
248 | |
249 | int linux_spi_read(unsigned char *rb, unsigned long rlen) | |
250 | { | |
251 | int ret; | |
252 | ||
253 | if (rlen > 0) { | |
254 | int i = 0; | |
255 | ||
256 | int blk = rlen / TXRX_PHASE_SIZE; | |
257 | int remainder = rlen % TXRX_PHASE_SIZE; | |
258 | ||
37bc15d8 | 259 | char *t_buffer = kzalloc(TXRX_PHASE_SIZE, GFP_KERNEL); |
8dfaafd6 | 260 | |
c5c77ba1 JK |
261 | if (!t_buffer) { |
262 | PRINT_ER("Failed to allocate memory for t_buffer\n"); | |
263 | } | |
264 | ||
265 | if (blk) { | |
266 | while (i < blk) { | |
267 | struct spi_message msg; | |
268 | struct spi_transfer tr = { | |
c5c77ba1 JK |
269 | .rx_buf = rb + (i * TXRX_PHASE_SIZE), |
270 | .len = TXRX_PHASE_SIZE, | |
271 | .speed_hz = SPEED, | |
272 | .bits_per_word = 8, | |
273 | .delay_usecs = 0, | |
274 | }; | |
275 | tr.tx_buf = t_buffer; | |
276 | ||
277 | memset(&msg, 0, sizeof(msg)); | |
278 | spi_message_init(&msg); | |
279 | msg.spi = wilc_spi_dev; | |
280 | msg.is_dma_mapped = USE_SPI_DMA; | |
281 | ||
282 | spi_message_add_tail(&tr, &msg); | |
283 | ret = spi_sync(wilc_spi_dev, &msg); | |
284 | if (ret < 0) { | |
285 | PRINT_ER("SPI transaction failed\n"); | |
286 | } | |
287 | i++; | |
288 | } | |
289 | } | |
290 | if (remainder) { | |
291 | struct spi_message msg; | |
292 | struct spi_transfer tr = { | |
c5c77ba1 JK |
293 | .rx_buf = rb + (blk * TXRX_PHASE_SIZE), |
294 | .len = remainder, | |
295 | .speed_hz = SPEED, | |
296 | .bits_per_word = 8, | |
297 | .delay_usecs = 0, | |
298 | }; | |
c5c77ba1 JK |
299 | tr.tx_buf = t_buffer; |
300 | ||
301 | memset(&msg, 0, sizeof(msg)); | |
302 | spi_message_init(&msg); | |
303 | msg.spi = wilc_spi_dev; | |
304 | msg.is_dma_mapped = USE_SPI_DMA; /* rachel */ | |
305 | ||
306 | spi_message_add_tail(&tr, &msg); | |
307 | ret = spi_sync(wilc_spi_dev, &msg); | |
308 | if (ret < 0) { | |
309 | PRINT_ER("SPI transaction failed\n"); | |
310 | } | |
311 | } | |
312 | ||
0256b540 | 313 | kfree(t_buffer); |
c5c77ba1 JK |
314 | } else { |
315 | PRINT_ER("can't read data with the following length: %ld\n", rlen); | |
316 | ret = -1; | |
317 | } | |
318 | /* change return value to match WILC interface */ | |
319 | (ret < 0) ? (ret = 0) : (ret = 1); | |
320 | ||
321 | return ret; | |
322 | } | |
323 | ||
324 | #else | |
325 | int linux_spi_read(unsigned char *rb, unsigned long rlen) | |
326 | { | |
327 | ||
328 | int ret; | |
329 | ||
330 | if (rlen > 0) { | |
331 | struct spi_message msg; | |
332 | struct spi_transfer tr = { | |
c5c77ba1 JK |
333 | .rx_buf = rb, |
334 | .len = rlen, | |
335 | .speed_hz = SPEED, | |
336 | .delay_usecs = 0, | |
337 | ||
338 | }; | |
37bc15d8 | 339 | char *t_buffer = kzalloc(rlen, GFP_KERNEL); |
8dfaafd6 | 340 | |
c5c77ba1 JK |
341 | if (!t_buffer) { |
342 | PRINT_ER("Failed to allocate memory for t_buffer\n"); | |
343 | } | |
344 | tr.tx_buf = t_buffer; | |
345 | ||
346 | memset(&msg, 0, sizeof(msg)); | |
347 | spi_message_init(&msg); | |
348 | /* [[ johnny add */ | |
349 | msg.spi = wilc_spi_dev; | |
350 | msg.is_dma_mapped = USE_SPI_DMA; | |
351 | /* ]] */ | |
352 | spi_message_add_tail(&tr, &msg); | |
353 | ||
354 | ret = spi_sync(wilc_spi_dev, &msg); | |
355 | if (ret < 0) { | |
356 | PRINT_ER("SPI transaction failed\n"); | |
357 | } | |
358 | kfree(t_buffer); | |
359 | } else { | |
360 | PRINT_ER("can't read data with the following length: %ld\n", rlen); | |
361 | ret = -1; | |
362 | } | |
363 | /* change return value to match WILC interface */ | |
364 | (ret < 0) ? (ret = 0) : (ret = 1); | |
365 | ||
366 | return ret; | |
367 | } | |
368 | ||
369 | #endif | |
370 | ||
371 | int linux_spi_write_read(unsigned char *wb, unsigned char *rb, unsigned int rlen) | |
372 | { | |
373 | ||
374 | int ret; | |
375 | ||
376 | if (rlen > 0) { | |
377 | struct spi_message msg; | |
378 | struct spi_transfer tr = { | |
379 | .rx_buf = rb, | |
380 | .tx_buf = wb, | |
381 | .len = rlen, | |
382 | .speed_hz = SPEED, | |
383 | .bits_per_word = 8, | |
384 | .delay_usecs = 0, | |
385 | ||
386 | }; | |
387 | ||
388 | memset(&msg, 0, sizeof(msg)); | |
389 | spi_message_init(&msg); | |
390 | msg.spi = wilc_spi_dev; | |
391 | msg.is_dma_mapped = USE_SPI_DMA; | |
392 | ||
393 | spi_message_add_tail(&tr, &msg); | |
394 | ret = spi_sync(wilc_spi_dev, &msg); | |
395 | if (ret < 0) { | |
396 | PRINT_ER("SPI transaction failed\n"); | |
397 | } | |
398 | } else { | |
399 | PRINT_ER("can't read data with the following length: %d\n", rlen); | |
400 | ret = -1; | |
401 | } | |
402 | /* change return value to match WILC interface */ | |
403 | (ret < 0) ? (ret = 0) : (ret = 1); | |
404 | ||
405 | return ret; | |
406 | } | |
407 | ||
408 | int linux_spi_set_max_speed(void) | |
409 | { | |
410 | SPEED = MAX_SPEED; | |
411 | ||
412 | PRINT_INFO(BUS_DBG, "@@@@@@@@@@@@ change SPI speed to %d @@@@@@@@@\n", SPEED); | |
413 | return 1; | |
414 | } |