blob: a8311a83ae96226ce7d07a22980029a0db1511a8 [file] [log] [blame]
Wu, Bryana5f6abd2007-05-06 14:50:34 -07001/*
Bryan Wu131b17d2007-12-04 23:45:12 -08002 * File: drivers/spi/bfin5xx_spi.c
3 * Maintainer:
4 * Bryan Wu <bryan.wu@analog.com>
5 * Original Author:
6 * Luke Yang (Analog Devices Inc.)
Wu, Bryana5f6abd2007-05-06 14:50:34 -07007 *
Bryan Wu131b17d2007-12-04 23:45:12 -08008 * Created: March. 10th 2006
9 * Description: SPI controller driver for Blackfin BF5xx
10 * Bugs: Enter bugs at http://blackfin.uclinux.org/
Wu, Bryana5f6abd2007-05-06 14:50:34 -070011 *
12 * Modified:
13 * March 10, 2006 bfin5xx_spi.c Created. (Luke Yang)
14 * August 7, 2006 added full duplex mode (Axel Weiss & Luke Yang)
Bryan Wu131b17d2007-12-04 23:45:12 -080015 * July 17, 2007 add support for BF54x SPI0 controller (Bryan Wu)
Bryan Wua32c6912007-12-04 23:45:15 -080016 * July 30, 2007 add platfrom_resource interface to support multi-port
17 * SPI controller (Bryan Wu)
Wu, Bryana5f6abd2007-05-06 14:50:34 -070018 *
Bryan Wu131b17d2007-12-04 23:45:12 -080019 * Copyright 2004-2007 Analog Devices Inc.
Wu, Bryana5f6abd2007-05-06 14:50:34 -070020 *
21 * This program is free software ; you can redistribute it and/or modify
22 * it under the terms of the GNU General Public License as published by
23 * the Free Software Foundation ; either version 2, or (at your option)
24 * any later version.
25 *
26 * This program is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY ; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 * GNU General Public License for more details.
30 *
31 * You should have received a copy of the GNU General Public License
32 * along with this program ; see the file COPYING.
33 * If not, write to the Free Software Foundation,
34 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
35 */
36
37#include <linux/init.h>
38#include <linux/module.h>
Bryan Wu131b17d2007-12-04 23:45:12 -080039#include <linux/delay.h>
Wu, Bryana5f6abd2007-05-06 14:50:34 -070040#include <linux/device.h>
Bryan Wu131b17d2007-12-04 23:45:12 -080041#include <linux/io.h>
Wu, Bryana5f6abd2007-05-06 14:50:34 -070042#include <linux/ioport.h>
Bryan Wu131b17d2007-12-04 23:45:12 -080043#include <linux/irq.h>
Wu, Bryana5f6abd2007-05-06 14:50:34 -070044#include <linux/errno.h>
45#include <linux/interrupt.h>
46#include <linux/platform_device.h>
47#include <linux/dma-mapping.h>
48#include <linux/spi/spi.h>
49#include <linux/workqueue.h>
Wu, Bryana5f6abd2007-05-06 14:50:34 -070050
Wu, Bryana5f6abd2007-05-06 14:50:34 -070051#include <asm/dma.h>
Bryan Wu131b17d2007-12-04 23:45:12 -080052#include <asm/portmux.h>
Wu, Bryana5f6abd2007-05-06 14:50:34 -070053#include <asm/bfin5xx_spi.h>
54
Bryan Wua32c6912007-12-04 23:45:15 -080055#define DRV_NAME "bfin-spi"
56#define DRV_AUTHOR "Bryan Wu, Luke Yang"
57#define DRV_DESC "Blackfin BF5xx on-chip SPI Contoller Driver"
58#define DRV_VERSION "1.0"
59
60MODULE_AUTHOR(DRV_AUTHOR);
61MODULE_DESCRIPTION(DRV_DESC);
Wu, Bryana5f6abd2007-05-06 14:50:34 -070062MODULE_LICENSE("GPL");
63
64#define IS_DMA_ALIGNED(x) (((u32)(x)&0x07)==0)
65
Bryan Wua32c6912007-12-04 23:45:15 -080066static u32 spi_dma_ch;
67static u32 spi_regs_base;
68
Wu, Bryana5f6abd2007-05-06 14:50:34 -070069#define DEFINE_SPI_REG(reg, off) \
70static inline u16 read_##reg(void) \
Bryan Wua32c6912007-12-04 23:45:15 -080071 { return bfin_read16(spi_regs_base + off); } \
Wu, Bryana5f6abd2007-05-06 14:50:34 -070072static inline void write_##reg(u16 v) \
Bryan Wua32c6912007-12-04 23:45:15 -080073 {bfin_write16(spi_regs_base + off, v); }
Wu, Bryana5f6abd2007-05-06 14:50:34 -070074
75DEFINE_SPI_REG(CTRL, 0x00)
76DEFINE_SPI_REG(FLAG, 0x04)
77DEFINE_SPI_REG(STAT, 0x08)
78DEFINE_SPI_REG(TDBR, 0x0C)
79DEFINE_SPI_REG(RDBR, 0x10)
80DEFINE_SPI_REG(BAUD, 0x14)
81DEFINE_SPI_REG(SHAW, 0x18)
82#define START_STATE ((void*)0)
83#define RUNNING_STATE ((void*)1)
84#define DONE_STATE ((void*)2)
85#define ERROR_STATE ((void*)-1)
86#define QUEUE_RUNNING 0
87#define QUEUE_STOPPED 1
88int dma_requested;
89
90struct driver_data {
91 /* Driver model hookup */
92 struct platform_device *pdev;
93
94 /* SPI framework hookup */
95 struct spi_master *master;
96
97 /* BFIN hookup */
98 struct bfin5xx_spi_master *master_info;
99
100 /* Driver message queue */
101 struct workqueue_struct *workqueue;
102 struct work_struct pump_messages;
103 spinlock_t lock;
104 struct list_head queue;
105 int busy;
106 int run;
107
108 /* Message Transfer pump */
109 struct tasklet_struct pump_transfers;
110
111 /* Current message transfer state info */
112 struct spi_message *cur_msg;
113 struct spi_transfer *cur_transfer;
114 struct chip_data *cur_chip;
115 size_t len_in_bytes;
116 size_t len;
117 void *tx;
118 void *tx_end;
119 void *rx;
120 void *rx_end;
121 int dma_mapped;
122 dma_addr_t rx_dma;
123 dma_addr_t tx_dma;
124 size_t rx_map_len;
125 size_t tx_map_len;
126 u8 n_bytes;
Bryan Wufad91c82007-12-04 23:45:14 -0800127 int cs_change;
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700128 void (*write) (struct driver_data *);
129 void (*read) (struct driver_data *);
130 void (*duplex) (struct driver_data *);
131};
132
133struct chip_data {
134 u16 ctl_reg;
135 u16 baud;
136 u16 flag;
137
138 u8 chip_select_num;
Bryan Wu131b17d2007-12-04 23:45:12 -0800139 u8 chip_select_requested;
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700140 u8 n_bytes;
Bryan Wu88b40362007-05-21 18:32:16 +0800141 u8 width; /* 0 or 1 */
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700142 u8 enable_dma;
143 u8 bits_per_word; /* 8 or 16 */
144 u8 cs_change_per_word;
145 u8 cs_chg_udelay;
146 void (*write) (struct driver_data *);
147 void (*read) (struct driver_data *);
148 void (*duplex) (struct driver_data *);
149};
150
Bryan Wu88b40362007-05-21 18:32:16 +0800151static void bfin_spi_enable(struct driver_data *drv_data)
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700152{
153 u16 cr;
154
155 cr = read_CTRL();
156 write_CTRL(cr | BIT_CTL_ENABLE);
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700157}
158
Bryan Wu88b40362007-05-21 18:32:16 +0800159static void bfin_spi_disable(struct driver_data *drv_data)
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700160{
161 u16 cr;
162
163 cr = read_CTRL();
164 write_CTRL(cr & (~BIT_CTL_ENABLE));
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700165}
166
167/* Caculate the SPI_BAUD register value based on input HZ */
168static u16 hz_to_spi_baud(u32 speed_hz)
169{
170 u_long sclk = get_sclk();
171 u16 spi_baud = (sclk / (2 * speed_hz));
172
173 if ((sclk % (2 * speed_hz)) > 0)
174 spi_baud++;
175
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700176 return spi_baud;
177}
178
179static int flush(struct driver_data *drv_data)
180{
181 unsigned long limit = loops_per_jiffy << 1;
182
183 /* wait for stop and clear stat */
184 while (!(read_STAT() & BIT_STAT_SPIF) && limit--)
185 continue;
186
187 write_STAT(BIT_STAT_CLR);
188
189 return limit;
190}
191
Bryan Wufad91c82007-12-04 23:45:14 -0800192/* Chip select operation functions for cs_change flag */
193static void cs_active(struct chip_data *chip)
194{
195 u16 flag = read_FLAG();
196
197 flag |= chip->flag;
198 flag &= ~(chip->flag << 8);
199
200 write_FLAG(flag);
201}
202
203static void cs_deactive(struct chip_data *chip)
204{
205 u16 flag = read_FLAG();
206
207 flag |= (chip->flag << 8);
208
209 write_FLAG(flag);
210}
211
Bryan Wu5fec5b52007-12-04 23:45:13 -0800212#define MAX_SPI0_SSEL 7
213
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700214/* stop controller and re-config current chip*/
Bryan Wu5fec5b52007-12-04 23:45:13 -0800215static int restore_state(struct driver_data *drv_data)
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700216{
217 struct chip_data *chip = drv_data->cur_chip;
Bryan Wu5fec5b52007-12-04 23:45:13 -0800218 int ret = 0;
219 u16 ssel[MAX_SPI0_SSEL] = {P_SPI0_SSEL1, P_SPI0_SSEL2, P_SPI0_SSEL3,
220 P_SPI0_SSEL4, P_SPI0_SSEL5,
221 P_SPI0_SSEL6, P_SPI0_SSEL7,};
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700222
223 /* Clear status and disable clock */
224 write_STAT(BIT_STAT_CLR);
225 bfin_spi_disable(drv_data);
Bryan Wu88b40362007-05-21 18:32:16 +0800226 dev_dbg(&drv_data->pdev->dev, "restoring spi ctl state\n");
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700227
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700228 /* Load the registers */
229 write_CTRL(chip->ctl_reg);
230 write_BAUD(chip->baud);
Bryan Wufad91c82007-12-04 23:45:14 -0800231 cs_active(chip);
Bryan Wu5fec5b52007-12-04 23:45:13 -0800232
233 if (!chip->chip_select_requested) {
234 int i = chip->chip_select_num;
235
236 dev_dbg(&drv_data->pdev->dev, "chip select number is %d\n", i);
237
238 if ((i > 0) && (i <= MAX_SPI0_SSEL))
239 ret = peripheral_request(ssel[i-1], DRV_NAME);
240
241 chip->chip_select_requested = 1;
242 }
243
244 if (ret)
245 dev_dbg(&drv_data->pdev->dev,
246 ": request chip select number %d failed\n",
247 chip->chip_select_num);
248
249 return ret;
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700250}
251
252/* used to kick off transfer in rx mode */
253static unsigned short dummy_read(void)
254{
255 unsigned short tmp;
256 tmp = read_RDBR();
257 return tmp;
258}
259
260static void null_writer(struct driver_data *drv_data)
261{
262 u8 n_bytes = drv_data->n_bytes;
263
264 while (drv_data->tx < drv_data->tx_end) {
265 write_TDBR(0);
266 while ((read_STAT() & BIT_STAT_TXS))
267 continue;
268 drv_data->tx += n_bytes;
269 }
270}
271
272static void null_reader(struct driver_data *drv_data)
273{
274 u8 n_bytes = drv_data->n_bytes;
275 dummy_read();
276
277 while (drv_data->rx < drv_data->rx_end) {
278 while (!(read_STAT() & BIT_STAT_RXS))
279 continue;
280 dummy_read();
281 drv_data->rx += n_bytes;
282 }
283}
284
285static void u8_writer(struct driver_data *drv_data)
286{
Bryan Wu131b17d2007-12-04 23:45:12 -0800287 dev_dbg(&drv_data->pdev->dev,
Bryan Wu88b40362007-05-21 18:32:16 +0800288 "cr8-s is 0x%x\n", read_STAT());
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700289 while (drv_data->tx < drv_data->tx_end) {
290 write_TDBR(*(u8 *) (drv_data->tx));
291 while (read_STAT() & BIT_STAT_TXS)
292 continue;
293 ++drv_data->tx;
294 }
295
296 /* poll for SPI completion before returning */
297 while (!(read_STAT() & BIT_STAT_SPIF))
298 continue;
299}
300
301static void u8_cs_chg_writer(struct driver_data *drv_data)
302{
303 struct chip_data *chip = drv_data->cur_chip;
304
305 while (drv_data->tx < drv_data->tx_end) {
Bryan Wufad91c82007-12-04 23:45:14 -0800306 cs_active(chip);
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700307
308 write_TDBR(*(u8 *) (drv_data->tx));
309 while (read_STAT() & BIT_STAT_TXS)
310 continue;
311 while (!(read_STAT() & BIT_STAT_SPIF))
312 continue;
Bryan Wufad91c82007-12-04 23:45:14 -0800313 cs_deactive(chip);
Bryan Wu5fec5b52007-12-04 23:45:13 -0800314
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700315 if (chip->cs_chg_udelay)
316 udelay(chip->cs_chg_udelay);
317 ++drv_data->tx;
318 }
Bryan Wufad91c82007-12-04 23:45:14 -0800319 cs_deactive(chip);
Bryan Wu5fec5b52007-12-04 23:45:13 -0800320
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700321}
322
323static void u8_reader(struct driver_data *drv_data)
324{
Bryan Wu131b17d2007-12-04 23:45:12 -0800325 dev_dbg(&drv_data->pdev->dev,
Bryan Wu88b40362007-05-21 18:32:16 +0800326 "cr-8 is 0x%x\n", read_STAT());
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700327
328 /* clear TDBR buffer before read(else it will be shifted out) */
329 write_TDBR(0xFFFF);
330
331 dummy_read();
332
333 while (drv_data->rx < drv_data->rx_end - 1) {
334 while (!(read_STAT() & BIT_STAT_RXS))
335 continue;
336 *(u8 *) (drv_data->rx) = read_RDBR();
337 ++drv_data->rx;
338 }
339
340 while (!(read_STAT() & BIT_STAT_RXS))
341 continue;
342 *(u8 *) (drv_data->rx) = read_SHAW();
343 ++drv_data->rx;
344}
345
346static void u8_cs_chg_reader(struct driver_data *drv_data)
347{
348 struct chip_data *chip = drv_data->cur_chip;
349
350 while (drv_data->rx < drv_data->rx_end) {
Bryan Wufad91c82007-12-04 23:45:14 -0800351 cs_active(chip);
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700352
353 read_RDBR(); /* kick off */
354 while (!(read_STAT() & BIT_STAT_RXS))
355 continue;
356 while (!(read_STAT() & BIT_STAT_SPIF))
357 continue;
358 *(u8 *) (drv_data->rx) = read_SHAW();
Bryan Wufad91c82007-12-04 23:45:14 -0800359 cs_deactive(chip);
Bryan Wu5fec5b52007-12-04 23:45:13 -0800360
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700361 if (chip->cs_chg_udelay)
362 udelay(chip->cs_chg_udelay);
363 ++drv_data->rx;
364 }
Bryan Wufad91c82007-12-04 23:45:14 -0800365 cs_deactive(chip);
Bryan Wu5fec5b52007-12-04 23:45:13 -0800366
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700367}
368
369static void u8_duplex(struct driver_data *drv_data)
370{
371 /* in duplex mode, clk is triggered by writing of TDBR */
372 while (drv_data->rx < drv_data->rx_end) {
373 write_TDBR(*(u8 *) (drv_data->tx));
374 while (!(read_STAT() & BIT_STAT_SPIF))
375 continue;
376 while (!(read_STAT() & BIT_STAT_RXS))
377 continue;
378 *(u8 *) (drv_data->rx) = read_RDBR();
379 ++drv_data->rx;
380 ++drv_data->tx;
381 }
382}
383
384static void u8_cs_chg_duplex(struct driver_data *drv_data)
385{
386 struct chip_data *chip = drv_data->cur_chip;
387
388 while (drv_data->rx < drv_data->rx_end) {
Bryan Wufad91c82007-12-04 23:45:14 -0800389 cs_active(chip);
Bryan Wu5fec5b52007-12-04 23:45:13 -0800390
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700391
392 write_TDBR(*(u8 *) (drv_data->tx));
393 while (!(read_STAT() & BIT_STAT_SPIF))
394 continue;
395 while (!(read_STAT() & BIT_STAT_RXS))
396 continue;
397 *(u8 *) (drv_data->rx) = read_RDBR();
Bryan Wufad91c82007-12-04 23:45:14 -0800398 cs_deactive(chip);
Bryan Wu5fec5b52007-12-04 23:45:13 -0800399
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700400 if (chip->cs_chg_udelay)
401 udelay(chip->cs_chg_udelay);
402 ++drv_data->rx;
403 ++drv_data->tx;
404 }
Bryan Wufad91c82007-12-04 23:45:14 -0800405 cs_deactive(chip);
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700406}
407
408static void u16_writer(struct driver_data *drv_data)
409{
Bryan Wu131b17d2007-12-04 23:45:12 -0800410 dev_dbg(&drv_data->pdev->dev,
Bryan Wu88b40362007-05-21 18:32:16 +0800411 "cr16 is 0x%x\n", read_STAT());
412
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700413 while (drv_data->tx < drv_data->tx_end) {
414 write_TDBR(*(u16 *) (drv_data->tx));
415 while ((read_STAT() & BIT_STAT_TXS))
416 continue;
417 drv_data->tx += 2;
418 }
419
420 /* poll for SPI completion before returning */
421 while (!(read_STAT() & BIT_STAT_SPIF))
422 continue;
423}
424
425static void u16_cs_chg_writer(struct driver_data *drv_data)
426{
427 struct chip_data *chip = drv_data->cur_chip;
428
429 while (drv_data->tx < drv_data->tx_end) {
Bryan Wufad91c82007-12-04 23:45:14 -0800430 cs_active(chip);
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700431
432 write_TDBR(*(u16 *) (drv_data->tx));
433 while ((read_STAT() & BIT_STAT_TXS))
434 continue;
435 while (!(read_STAT() & BIT_STAT_SPIF))
436 continue;
Bryan Wufad91c82007-12-04 23:45:14 -0800437 cs_deactive(chip);
Bryan Wu5fec5b52007-12-04 23:45:13 -0800438
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700439 if (chip->cs_chg_udelay)
440 udelay(chip->cs_chg_udelay);
441 drv_data->tx += 2;
442 }
Bryan Wufad91c82007-12-04 23:45:14 -0800443 cs_deactive(chip);
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700444}
445
446static void u16_reader(struct driver_data *drv_data)
447{
Bryan Wu88b40362007-05-21 18:32:16 +0800448 dev_dbg(&drv_data->pdev->dev,
449 "cr-16 is 0x%x\n", read_STAT());
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700450 dummy_read();
451
452 while (drv_data->rx < (drv_data->rx_end - 2)) {
453 while (!(read_STAT() & BIT_STAT_RXS))
454 continue;
455 *(u16 *) (drv_data->rx) = read_RDBR();
456 drv_data->rx += 2;
457 }
458
459 while (!(read_STAT() & BIT_STAT_RXS))
460 continue;
461 *(u16 *) (drv_data->rx) = read_SHAW();
462 drv_data->rx += 2;
463}
464
465static void u16_cs_chg_reader(struct driver_data *drv_data)
466{
467 struct chip_data *chip = drv_data->cur_chip;
468
469 while (drv_data->rx < drv_data->rx_end) {
Bryan Wufad91c82007-12-04 23:45:14 -0800470 cs_active(chip);
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700471
472 read_RDBR(); /* kick off */
473 while (!(read_STAT() & BIT_STAT_RXS))
474 continue;
475 while (!(read_STAT() & BIT_STAT_SPIF))
476 continue;
477 *(u16 *) (drv_data->rx) = read_SHAW();
Bryan Wufad91c82007-12-04 23:45:14 -0800478 cs_deactive(chip);
Bryan Wu5fec5b52007-12-04 23:45:13 -0800479
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700480 if (chip->cs_chg_udelay)
481 udelay(chip->cs_chg_udelay);
482 drv_data->rx += 2;
483 }
Bryan Wufad91c82007-12-04 23:45:14 -0800484 cs_deactive(chip);
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700485}
486
487static void u16_duplex(struct driver_data *drv_data)
488{
489 /* in duplex mode, clk is triggered by writing of TDBR */
490 while (drv_data->tx < drv_data->tx_end) {
491 write_TDBR(*(u16 *) (drv_data->tx));
492 while (!(read_STAT() & BIT_STAT_SPIF))
493 continue;
494 while (!(read_STAT() & BIT_STAT_RXS))
495 continue;
496 *(u16 *) (drv_data->rx) = read_RDBR();
497 drv_data->rx += 2;
498 drv_data->tx += 2;
499 }
500}
501
502static void u16_cs_chg_duplex(struct driver_data *drv_data)
503{
504 struct chip_data *chip = drv_data->cur_chip;
505
506 while (drv_data->tx < drv_data->tx_end) {
Bryan Wufad91c82007-12-04 23:45:14 -0800507 cs_active(chip);
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700508
509 write_TDBR(*(u16 *) (drv_data->tx));
510 while (!(read_STAT() & BIT_STAT_SPIF))
511 continue;
512 while (!(read_STAT() & BIT_STAT_RXS))
513 continue;
514 *(u16 *) (drv_data->rx) = read_RDBR();
Bryan Wufad91c82007-12-04 23:45:14 -0800515 cs_deactive(chip);
Bryan Wu5fec5b52007-12-04 23:45:13 -0800516
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700517 if (chip->cs_chg_udelay)
518 udelay(chip->cs_chg_udelay);
519 drv_data->rx += 2;
520 drv_data->tx += 2;
521 }
Bryan Wufad91c82007-12-04 23:45:14 -0800522 cs_deactive(chip);
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700523}
524
525/* test if ther is more transfer to be done */
526static void *next_transfer(struct driver_data *drv_data)
527{
528 struct spi_message *msg = drv_data->cur_msg;
529 struct spi_transfer *trans = drv_data->cur_transfer;
530
531 /* Move to next transfer */
532 if (trans->transfer_list.next != &msg->transfers) {
533 drv_data->cur_transfer =
534 list_entry(trans->transfer_list.next,
535 struct spi_transfer, transfer_list);
536 return RUNNING_STATE;
537 } else
538 return DONE_STATE;
539}
540
541/*
542 * caller already set message->status;
543 * dma and pio irqs are blocked give finished message back
544 */
545static void giveback(struct driver_data *drv_data)
546{
Bryan Wufad91c82007-12-04 23:45:14 -0800547 struct chip_data *chip = drv_data->cur_chip;
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700548 struct spi_transfer *last_transfer;
549 unsigned long flags;
550 struct spi_message *msg;
551
552 spin_lock_irqsave(&drv_data->lock, flags);
553 msg = drv_data->cur_msg;
554 drv_data->cur_msg = NULL;
555 drv_data->cur_transfer = NULL;
556 drv_data->cur_chip = NULL;
557 queue_work(drv_data->workqueue, &drv_data->pump_messages);
558 spin_unlock_irqrestore(&drv_data->lock, flags);
559
560 last_transfer = list_entry(msg->transfers.prev,
561 struct spi_transfer, transfer_list);
562
563 msg->state = NULL;
564
565 /* disable chip select signal. And not stop spi in autobuffer mode */
566 if (drv_data->tx_dma != 0xFFFF) {
Bryan Wufad91c82007-12-04 23:45:14 -0800567 cs_deactive(chip);
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700568 bfin_spi_disable(drv_data);
569 }
570
Bryan Wufad91c82007-12-04 23:45:14 -0800571 if (!drv_data->cs_change)
572 cs_deactive(chip);
573
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700574 if (msg->complete)
575 msg->complete(msg->context);
576}
577
Bryan Wu88b40362007-05-21 18:32:16 +0800578static irqreturn_t dma_irq_handler(int irq, void *dev_id)
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700579{
580 struct driver_data *drv_data = (struct driver_data *)dev_id;
581 struct spi_message *msg = drv_data->cur_msg;
Bryan Wufad91c82007-12-04 23:45:14 -0800582 struct chip_data *chip = drv_data->cur_chip;
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700583
Bryan Wu88b40362007-05-21 18:32:16 +0800584 dev_dbg(&drv_data->pdev->dev, "in dma_irq_handler\n");
Bryan Wua32c6912007-12-04 23:45:15 -0800585 clear_dma_irqstat(spi_dma_ch);
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700586
Bryan Wud6fe89b2007-06-11 17:34:17 +0800587 /* Wait for DMA to complete */
Bryan Wua32c6912007-12-04 23:45:15 -0800588 while (get_dma_curr_irqstat(spi_dma_ch) & DMA_RUN)
Bryan Wud6fe89b2007-06-11 17:34:17 +0800589 continue;
590
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700591 /*
Bryan Wud6fe89b2007-06-11 17:34:17 +0800592 * wait for the last transaction shifted out. HRM states:
593 * at this point there may still be data in the SPI DMA FIFO waiting
594 * to be transmitted ... software needs to poll TXS in the SPI_STAT
595 * register until it goes low for 2 successive reads
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700596 */
597 if (drv_data->tx != NULL) {
Bryan Wua32c6912007-12-04 23:45:15 -0800598 while ((read_STAT() & TXS) ||
599 (read_STAT() & TXS))
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700600 continue;
601 }
602
Bryan Wua32c6912007-12-04 23:45:15 -0800603 while (!(read_STAT() & SPIF))
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700604 continue;
605
606 bfin_spi_disable(drv_data);
607
608 msg->actual_length += drv_data->len_in_bytes;
609
Bryan Wufad91c82007-12-04 23:45:14 -0800610 if (drv_data->cs_change)
611 cs_deactive(chip);
612
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700613 /* Move to next transfer */
614 msg->state = next_transfer(drv_data);
615
616 /* Schedule transfer tasklet */
617 tasklet_schedule(&drv_data->pump_transfers);
618
619 /* free the irq handler before next transfer */
Bryan Wu88b40362007-05-21 18:32:16 +0800620 dev_dbg(&drv_data->pdev->dev,
621 "disable dma channel irq%d\n",
Bryan Wua32c6912007-12-04 23:45:15 -0800622 spi_dma_ch);
623 dma_disable_irq(spi_dma_ch);
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700624
625 return IRQ_HANDLED;
626}
627
628static void pump_transfers(unsigned long data)
629{
630 struct driver_data *drv_data = (struct driver_data *)data;
631 struct spi_message *message = NULL;
632 struct spi_transfer *transfer = NULL;
633 struct spi_transfer *previous = NULL;
634 struct chip_data *chip = NULL;
Bryan Wu88b40362007-05-21 18:32:16 +0800635 u8 width;
636 u16 cr, dma_width, dma_config;
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700637 u32 tranf_success = 1;
638
639 /* Get current state information */
640 message = drv_data->cur_msg;
641 transfer = drv_data->cur_transfer;
642 chip = drv_data->cur_chip;
643
644 /*
645 * if msg is error or done, report it back using complete() callback
646 */
647
648 /* Handle for abort */
649 if (message->state == ERROR_STATE) {
650 message->status = -EIO;
651 giveback(drv_data);
652 return;
653 }
654
655 /* Handle end of message */
656 if (message->state == DONE_STATE) {
657 message->status = 0;
658 giveback(drv_data);
659 return;
660 }
661
662 /* Delay if requested at end of transfer */
663 if (message->state == RUNNING_STATE) {
664 previous = list_entry(transfer->transfer_list.prev,
665 struct spi_transfer, transfer_list);
666 if (previous->delay_usecs)
667 udelay(previous->delay_usecs);
668 }
669
670 /* Setup the transfer state based on the type of transfer */
671 if (flush(drv_data) == 0) {
672 dev_err(&drv_data->pdev->dev, "pump_transfers: flush failed\n");
673 message->status = -EIO;
674 giveback(drv_data);
675 return;
676 }
677
678 if (transfer->tx_buf != NULL) {
679 drv_data->tx = (void *)transfer->tx_buf;
680 drv_data->tx_end = drv_data->tx + transfer->len;
Bryan Wu88b40362007-05-21 18:32:16 +0800681 dev_dbg(&drv_data->pdev->dev, "tx_buf is %p, tx_end is %p\n",
682 transfer->tx_buf, drv_data->tx_end);
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700683 } else {
684 drv_data->tx = NULL;
685 }
686
687 if (transfer->rx_buf != NULL) {
688 drv_data->rx = transfer->rx_buf;
689 drv_data->rx_end = drv_data->rx + transfer->len;
Bryan Wu88b40362007-05-21 18:32:16 +0800690 dev_dbg(&drv_data->pdev->dev, "rx_buf is %p, rx_end is %p\n",
691 transfer->rx_buf, drv_data->rx_end);
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700692 } else {
693 drv_data->rx = NULL;
694 }
695
696 drv_data->rx_dma = transfer->rx_dma;
697 drv_data->tx_dma = transfer->tx_dma;
698 drv_data->len_in_bytes = transfer->len;
Bryan Wufad91c82007-12-04 23:45:14 -0800699 drv_data->cs_change = transfer->cs_change;
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700700
701 width = chip->width;
702 if (width == CFG_SPI_WORDSIZE16) {
703 drv_data->len = (transfer->len) >> 1;
704 } else {
705 drv_data->len = transfer->len;
706 }
707 drv_data->write = drv_data->tx ? chip->write : null_writer;
708 drv_data->read = drv_data->rx ? chip->read : null_reader;
709 drv_data->duplex = chip->duplex ? chip->duplex : null_writer;
Bryan Wu131b17d2007-12-04 23:45:12 -0800710 dev_dbg(&drv_data->pdev->dev, "transfer: ",
711 "drv_data->write is %p, chip->write is %p, null_wr is %p\n",
712 drv_data->write, chip->write, null_writer);
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700713
714 /* speed and width has been set on per message */
715 message->state = RUNNING_STATE;
716 dma_config = 0;
717
718 /* restore spi status for each spi transfer */
719 if (transfer->speed_hz) {
720 write_BAUD(hz_to_spi_baud(transfer->speed_hz));
721 } else {
722 write_BAUD(chip->baud);
723 }
Bryan Wufad91c82007-12-04 23:45:14 -0800724 cs_active(chip);
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700725
Bryan Wu88b40362007-05-21 18:32:16 +0800726 dev_dbg(&drv_data->pdev->dev,
727 "now pumping a transfer: width is %d, len is %d\n",
728 width, transfer->len);
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700729
730 /*
731 * Try to map dma buffer and do a dma transfer if
732 * successful use different way to r/w according to
733 * drv_data->cur_chip->enable_dma
734 */
735 if (drv_data->cur_chip->enable_dma && drv_data->len > 6) {
736
737 write_STAT(BIT_STAT_CLR);
Bryan Wua32c6912007-12-04 23:45:15 -0800738 disable_dma(spi_dma_ch);
739 clear_dma_irqstat(spi_dma_ch);
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700740 bfin_spi_disable(drv_data);
741
742 /* config dma channel */
Bryan Wu88b40362007-05-21 18:32:16 +0800743 dev_dbg(&drv_data->pdev->dev, "doing dma transfer\n");
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700744 if (width == CFG_SPI_WORDSIZE16) {
Bryan Wua32c6912007-12-04 23:45:15 -0800745 set_dma_x_count(spi_dma_ch, drv_data->len);
746 set_dma_x_modify(spi_dma_ch, 2);
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700747 dma_width = WDSIZE_16;
748 } else {
Bryan Wua32c6912007-12-04 23:45:15 -0800749 set_dma_x_count(spi_dma_ch, drv_data->len);
750 set_dma_x_modify(spi_dma_ch, 1);
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700751 dma_width = WDSIZE_8;
752 }
753
754 /* set transfer width,direction. And enable spi */
755 cr = (read_CTRL() & (~BIT_CTL_TIMOD));
756
757 /* dirty hack for autobuffer DMA mode */
758 if (drv_data->tx_dma == 0xFFFF) {
Bryan Wu88b40362007-05-21 18:32:16 +0800759 dev_dbg(&drv_data->pdev->dev,
760 "doing autobuffer DMA out.\n");
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700761
762 /* no irq in autobuffer mode */
763 dma_config =
764 (DMAFLOW_AUTO | RESTART | dma_width | DI_EN);
Bryan Wua32c6912007-12-04 23:45:15 -0800765 set_dma_config(spi_dma_ch, dma_config);
766 set_dma_start_addr(spi_dma_ch,
767 (unsigned long)drv_data->tx);
768 enable_dma(spi_dma_ch);
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700769 write_CTRL(cr | CFG_SPI_DMAWRITE | (width << 8) |
770 (CFG_SPI_ENABLE << 14));
771
772 /* just return here, there can only be one transfer in this mode */
773 message->status = 0;
774 giveback(drv_data);
775 return;
776 }
777
778 /* In dma mode, rx or tx must be NULL in one transfer */
779 if (drv_data->rx != NULL) {
780 /* set transfer mode, and enable SPI */
Bryan Wu88b40362007-05-21 18:32:16 +0800781 dev_dbg(&drv_data->pdev->dev, "doing DMA in.\n");
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700782
783 /* disable SPI before write to TDBR */
784 write_CTRL(cr & ~BIT_CTL_ENABLE);
785
786 /* clear tx reg soformer data is not shifted out */
787 write_TDBR(0xFF);
788
Bryan Wua32c6912007-12-04 23:45:15 -0800789 set_dma_x_count(spi_dma_ch, drv_data->len);
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700790
791 /* start dma */
Bryan Wua32c6912007-12-04 23:45:15 -0800792 dma_enable_irq(spi_dma_ch);
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700793 dma_config = (WNR | RESTART | dma_width | DI_EN);
Bryan Wua32c6912007-12-04 23:45:15 -0800794 set_dma_config(spi_dma_ch, dma_config);
795 set_dma_start_addr(spi_dma_ch,
796 (unsigned long)drv_data->rx);
797 enable_dma(spi_dma_ch);
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700798
799 cr |=
800 CFG_SPI_DMAREAD | (width << 8) | (CFG_SPI_ENABLE <<
801 14);
802 /* set transfer mode, and enable SPI */
803 write_CTRL(cr);
804 } else if (drv_data->tx != NULL) {
Bryan Wu88b40362007-05-21 18:32:16 +0800805 dev_dbg(&drv_data->pdev->dev, "doing DMA out.\n");
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700806
807 /* start dma */
Bryan Wua32c6912007-12-04 23:45:15 -0800808 dma_enable_irq(spi_dma_ch);
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700809 dma_config = (RESTART | dma_width | DI_EN);
Bryan Wua32c6912007-12-04 23:45:15 -0800810 set_dma_config(spi_dma_ch, dma_config);
811 set_dma_start_addr(spi_dma_ch,
812 (unsigned long)drv_data->tx);
813 enable_dma(spi_dma_ch);
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700814
815 write_CTRL(cr | CFG_SPI_DMAWRITE | (width << 8) |
816 (CFG_SPI_ENABLE << 14));
817
818 }
819 } else {
820 /* IO mode write then read */
Bryan Wu88b40362007-05-21 18:32:16 +0800821 dev_dbg(&drv_data->pdev->dev, "doing IO transfer\n");
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700822
823 write_STAT(BIT_STAT_CLR);
824
825 if (drv_data->tx != NULL && drv_data->rx != NULL) {
826 /* full duplex mode */
827 BUG_ON((drv_data->tx_end - drv_data->tx) !=
828 (drv_data->rx_end - drv_data->rx));
Bryan Wu131b17d2007-12-04 23:45:12 -0800829 cr = (read_CTRL() & (~BIT_CTL_TIMOD));
Bryan Wu88b40362007-05-21 18:32:16 +0800830 cr |= CFG_SPI_WRITE | (width << 8) |
831 (CFG_SPI_ENABLE << 14);
832 dev_dbg(&drv_data->pdev->dev,
833 "IO duplex: cr is 0x%x\n", cr);
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700834
835 write_CTRL(cr);
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700836
837 drv_data->duplex(drv_data);
838
839 if (drv_data->tx != drv_data->tx_end)
840 tranf_success = 0;
841 } else if (drv_data->tx != NULL) {
842 /* write only half duplex */
Bryan Wu88b40362007-05-21 18:32:16 +0800843 cr = (read_CTRL() & (~BIT_CTL_TIMOD));
844 cr |= CFG_SPI_WRITE | (width << 8) |
845 (CFG_SPI_ENABLE << 14);
Bryan Wu131b17d2007-12-04 23:45:12 -0800846 dev_dbg(&drv_data->pdev->dev,
Bryan Wu88b40362007-05-21 18:32:16 +0800847 "IO write: cr is 0x%x\n", cr);
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700848
849 write_CTRL(cr);
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700850
851 drv_data->write(drv_data);
852
853 if (drv_data->tx != drv_data->tx_end)
854 tranf_success = 0;
855 } else if (drv_data->rx != NULL) {
856 /* read only half duplex */
Bryan Wu88b40362007-05-21 18:32:16 +0800857 cr = (read_CTRL() & (~BIT_CTL_TIMOD));
858 cr |= CFG_SPI_READ | (width << 8) |
859 (CFG_SPI_ENABLE << 14);
Bryan Wu131b17d2007-12-04 23:45:12 -0800860 dev_dbg(&drv_data->pdev->dev,
Bryan Wu88b40362007-05-21 18:32:16 +0800861 "IO read: cr is 0x%x\n", cr);
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700862
863 write_CTRL(cr);
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700864
865 drv_data->read(drv_data);
866 if (drv_data->rx != drv_data->rx_end)
867 tranf_success = 0;
868 }
869
870 if (!tranf_success) {
Bryan Wu131b17d2007-12-04 23:45:12 -0800871 dev_dbg(&drv_data->pdev->dev,
Bryan Wu88b40362007-05-21 18:32:16 +0800872 "IO write error!\n");
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700873 message->state = ERROR_STATE;
874 } else {
875 /* Update total byte transfered */
876 message->actual_length += drv_data->len;
877
Bryan Wufad91c82007-12-04 23:45:14 -0800878 if (drv_data->cs_change)
879 cs_deactive(chip);
880
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700881 /* Move to next transfer of this msg */
882 message->state = next_transfer(drv_data);
883 }
884
885 /* Schedule next transfer tasklet */
886 tasklet_schedule(&drv_data->pump_transfers);
887
888 }
889}
890
891/* pop a msg from queue and kick off real transfer */
892static void pump_messages(struct work_struct *work)
893{
Bryan Wu131b17d2007-12-04 23:45:12 -0800894 struct driver_data *drv_data;
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700895 unsigned long flags;
896
Bryan Wu131b17d2007-12-04 23:45:12 -0800897 drv_data = container_of(work, struct driver_data, pump_messages);
898
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700899 /* Lock queue and check for queue work */
900 spin_lock_irqsave(&drv_data->lock, flags);
901 if (list_empty(&drv_data->queue) || drv_data->run == QUEUE_STOPPED) {
902 /* pumper kicked off but no work to do */
903 drv_data->busy = 0;
904 spin_unlock_irqrestore(&drv_data->lock, flags);
905 return;
906 }
907
908 /* Make sure we are not already running a message */
909 if (drv_data->cur_msg) {
910 spin_unlock_irqrestore(&drv_data->lock, flags);
911 return;
912 }
913
914 /* Extract head of queue */
915 drv_data->cur_msg = list_entry(drv_data->queue.next,
916 struct spi_message, queue);
Bryan Wu5fec5b52007-12-04 23:45:13 -0800917
918 /* Setup the SSP using the per chip configuration */
919 drv_data->cur_chip = spi_get_ctldata(drv_data->cur_msg->spi);
920 if (restore_state(drv_data)) {
921 spin_unlock_irqrestore(&drv_data->lock, flags);
922 return;
923 };
924
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700925 list_del_init(&drv_data->cur_msg->queue);
926
927 /* Initial message state */
928 drv_data->cur_msg->state = START_STATE;
929 drv_data->cur_transfer = list_entry(drv_data->cur_msg->transfers.next,
930 struct spi_transfer, transfer_list);
931
Bryan Wu5fec5b52007-12-04 23:45:13 -0800932 dev_dbg(&drv_data->pdev->dev, "got a message to pump, "
933 "state is set to: baud %d, flag 0x%x, ctl 0x%x\n",
934 drv_data->cur_chip->baud, drv_data->cur_chip->flag,
935 drv_data->cur_chip->ctl_reg);
Bryan Wu131b17d2007-12-04 23:45:12 -0800936
937 dev_dbg(&drv_data->pdev->dev,
Bryan Wu88b40362007-05-21 18:32:16 +0800938 "the first transfer len is %d\n",
939 drv_data->cur_transfer->len);
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700940
941 /* Mark as busy and launch transfers */
942 tasklet_schedule(&drv_data->pump_transfers);
943
944 drv_data->busy = 1;
945 spin_unlock_irqrestore(&drv_data->lock, flags);
946}
947
948/*
949 * got a msg to transfer, queue it in drv_data->queue.
950 * And kick off message pumper
951 */
952static int transfer(struct spi_device *spi, struct spi_message *msg)
953{
954 struct driver_data *drv_data = spi_master_get_devdata(spi->master);
955 unsigned long flags;
956
957 spin_lock_irqsave(&drv_data->lock, flags);
958
959 if (drv_data->run == QUEUE_STOPPED) {
960 spin_unlock_irqrestore(&drv_data->lock, flags);
961 return -ESHUTDOWN;
962 }
963
964 msg->actual_length = 0;
965 msg->status = -EINPROGRESS;
966 msg->state = START_STATE;
967
Bryan Wu88b40362007-05-21 18:32:16 +0800968 dev_dbg(&spi->dev, "adding an msg in transfer() \n");
Wu, Bryana5f6abd2007-05-06 14:50:34 -0700969 list_add_tail(&msg->queue, &drv_data->queue);
970
971 if (drv_data->run == QUEUE_RUNNING && !drv_data->busy)
972 queue_work(drv_data->workqueue, &drv_data->pump_messages);
973
974 spin_unlock_irqrestore(&drv_data->lock, flags);
975
976 return 0;
977}
978
979/* first setup for new devices */
980static int setup(struct spi_device *spi)
981{
982 struct bfin5xx_spi_chip *chip_info = NULL;
983 struct chip_data *chip;
984 struct driver_data *drv_data = spi_master_get_devdata(spi->master);
985 u8 spi_flg;
986
987 /* Abort device setup if requested features are not supported */
988 if (spi->mode & ~(SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST)) {
989 dev_err(&spi->dev, "requested mode not fully supported\n");
990 return -EINVAL;
991 }
992
993 /* Zero (the default) here means 8 bits */
994 if (!spi->bits_per_word)
995 spi->bits_per_word = 8;
996
997 if (spi->bits_per_word != 8 && spi->bits_per_word != 16)
998 return -EINVAL;
999
1000 /* Only alloc (or use chip_info) on first setup */
1001 chip = spi_get_ctldata(spi);
1002 if (chip == NULL) {
1003 chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);
1004 if (!chip)
1005 return -ENOMEM;
1006
1007 chip->enable_dma = 0;
1008 chip_info = spi->controller_data;
1009 }
1010
1011 /* chip_info isn't always needed */
1012 if (chip_info) {
Mike Frysinger2ed35512007-12-04 23:45:14 -08001013 /* Make sure people stop trying to set fields via ctl_reg
1014 * when they should actually be using common SPI framework.
1015 * Currently we let through: WOM EMISO PSSE GM SZ TIMOD.
1016 * Not sure if a user actually needs/uses any of these,
1017 * but let's assume (for now) they do.
1018 */
1019 if (chip_info->ctl_reg & (SPE|MSTR|CPOL|CPHA|LSBF|SIZE)) {
1020 dev_err(&spi->dev, "do not set bits in ctl_reg "
1021 "that the SPI framework manages\n");
1022 return -EINVAL;
1023 }
1024
Wu, Bryana5f6abd2007-05-06 14:50:34 -07001025 chip->enable_dma = chip_info->enable_dma != 0
1026 && drv_data->master_info->enable_dma;
1027 chip->ctl_reg = chip_info->ctl_reg;
1028 chip->bits_per_word = chip_info->bits_per_word;
1029 chip->cs_change_per_word = chip_info->cs_change_per_word;
1030 chip->cs_chg_udelay = chip_info->cs_chg_udelay;
1031 }
1032
1033 /* translate common spi framework into our register */
1034 if (spi->mode & SPI_CPOL)
1035 chip->ctl_reg |= CPOL;
1036 if (spi->mode & SPI_CPHA)
1037 chip->ctl_reg |= CPHA;
1038 if (spi->mode & SPI_LSB_FIRST)
1039 chip->ctl_reg |= LSBF;
1040 /* we dont support running in slave mode (yet?) */
1041 chip->ctl_reg |= MSTR;
1042
1043 /*
1044 * if any one SPI chip is registered and wants DMA, request the
1045 * DMA channel for it
1046 */
1047 if (chip->enable_dma && !dma_requested) {
1048 /* register dma irq handler */
Bryan Wua32c6912007-12-04 23:45:15 -08001049 if (request_dma(spi_dma_ch, "BF53x_SPI_DMA") < 0) {
Bryan Wu88b40362007-05-21 18:32:16 +08001050 dev_dbg(&spi->dev,
1051 "Unable to request BlackFin SPI DMA channel\n");
Wu, Bryana5f6abd2007-05-06 14:50:34 -07001052 return -ENODEV;
1053 }
Bryan Wua32c6912007-12-04 23:45:15 -08001054 if (set_dma_callback(spi_dma_ch, (void *)dma_irq_handler,
1055 drv_data) < 0) {
Bryan Wu88b40362007-05-21 18:32:16 +08001056 dev_dbg(&spi->dev, "Unable to set dma callback\n");
Wu, Bryana5f6abd2007-05-06 14:50:34 -07001057 return -EPERM;
1058 }
Bryan Wua32c6912007-12-04 23:45:15 -08001059 dma_disable_irq(spi_dma_ch);
Wu, Bryana5f6abd2007-05-06 14:50:34 -07001060 dma_requested = 1;
1061 }
1062
1063 /*
1064 * Notice: for blackfin, the speed_hz is the value of register
1065 * SPI_BAUD, not the real baudrate
1066 */
1067 chip->baud = hz_to_spi_baud(spi->max_speed_hz);
1068 spi_flg = ~(1 << (spi->chip_select));
1069 chip->flag = ((u16) spi_flg << 8) | (1 << (spi->chip_select));
1070 chip->chip_select_num = spi->chip_select;
1071
1072 switch (chip->bits_per_word) {
1073 case 8:
1074 chip->n_bytes = 1;
1075 chip->width = CFG_SPI_WORDSIZE8;
1076 chip->read = chip->cs_change_per_word ?
1077 u8_cs_chg_reader : u8_reader;
1078 chip->write = chip->cs_change_per_word ?
1079 u8_cs_chg_writer : u8_writer;
1080 chip->duplex = chip->cs_change_per_word ?
1081 u8_cs_chg_duplex : u8_duplex;
1082 break;
1083
1084 case 16:
1085 chip->n_bytes = 2;
1086 chip->width = CFG_SPI_WORDSIZE16;
1087 chip->read = chip->cs_change_per_word ?
1088 u16_cs_chg_reader : u16_reader;
1089 chip->write = chip->cs_change_per_word ?
1090 u16_cs_chg_writer : u16_writer;
1091 chip->duplex = chip->cs_change_per_word ?
1092 u16_cs_chg_duplex : u16_duplex;
1093 break;
1094
1095 default:
1096 dev_err(&spi->dev, "%d bits_per_word is not supported\n",
1097 chip->bits_per_word);
1098 kfree(chip);
1099 return -ENODEV;
1100 }
1101
Joe Perches898eb712007-10-18 03:06:30 -07001102 dev_dbg(&spi->dev, "setup spi chip %s, width is %d, dma is %d\n",
Wu, Bryana5f6abd2007-05-06 14:50:34 -07001103 spi->modalias, chip->width, chip->enable_dma);
Bryan Wu88b40362007-05-21 18:32:16 +08001104 dev_dbg(&spi->dev, "ctl_reg is 0x%x, flag_reg is 0x%x\n",
Wu, Bryana5f6abd2007-05-06 14:50:34 -07001105 chip->ctl_reg, chip->flag);
1106
1107 spi_set_ctldata(spi, chip);
1108
1109 return 0;
1110}
1111
1112/*
1113 * callback for spi framework.
1114 * clean driver specific data
1115 */
Bryan Wu88b40362007-05-21 18:32:16 +08001116static void cleanup(struct spi_device *spi)
Wu, Bryana5f6abd2007-05-06 14:50:34 -07001117{
Mike Frysinger27bb9e72007-06-11 15:31:30 +08001118 struct chip_data *chip = spi_get_ctldata(spi);
Wu, Bryana5f6abd2007-05-06 14:50:34 -07001119
1120 kfree(chip);
1121}
1122
1123static inline int init_queue(struct driver_data *drv_data)
1124{
1125 INIT_LIST_HEAD(&drv_data->queue);
1126 spin_lock_init(&drv_data->lock);
1127
1128 drv_data->run = QUEUE_STOPPED;
1129 drv_data->busy = 0;
1130
1131 /* init transfer tasklet */
1132 tasklet_init(&drv_data->pump_transfers,
1133 pump_transfers, (unsigned long)drv_data);
1134
1135 /* init messages workqueue */
1136 INIT_WORK(&drv_data->pump_messages, pump_messages);
1137 drv_data->workqueue =
Tony Jones49dce682007-10-16 01:27:48 -07001138 create_singlethread_workqueue(drv_data->master->dev.parent->bus_id);
Wu, Bryana5f6abd2007-05-06 14:50:34 -07001139 if (drv_data->workqueue == NULL)
1140 return -EBUSY;
1141
1142 return 0;
1143}
1144
1145static inline int start_queue(struct driver_data *drv_data)
1146{
1147 unsigned long flags;
1148
1149 spin_lock_irqsave(&drv_data->lock, flags);
1150
1151 if (drv_data->run == QUEUE_RUNNING || drv_data->busy) {
1152 spin_unlock_irqrestore(&drv_data->lock, flags);
1153 return -EBUSY;
1154 }
1155
1156 drv_data->run = QUEUE_RUNNING;
1157 drv_data->cur_msg = NULL;
1158 drv_data->cur_transfer = NULL;
1159 drv_data->cur_chip = NULL;
1160 spin_unlock_irqrestore(&drv_data->lock, flags);
1161
1162 queue_work(drv_data->workqueue, &drv_data->pump_messages);
1163
1164 return 0;
1165}
1166
1167static inline int stop_queue(struct driver_data *drv_data)
1168{
1169 unsigned long flags;
1170 unsigned limit = 500;
1171 int status = 0;
1172
1173 spin_lock_irqsave(&drv_data->lock, flags);
1174
1175 /*
1176 * This is a bit lame, but is optimized for the common execution path.
1177 * A wait_queue on the drv_data->busy could be used, but then the common
1178 * execution path (pump_messages) would be required to call wake_up or
1179 * friends on every SPI message. Do this instead
1180 */
1181 drv_data->run = QUEUE_STOPPED;
1182 while (!list_empty(&drv_data->queue) && drv_data->busy && limit--) {
1183 spin_unlock_irqrestore(&drv_data->lock, flags);
1184 msleep(10);
1185 spin_lock_irqsave(&drv_data->lock, flags);
1186 }
1187
1188 if (!list_empty(&drv_data->queue) || drv_data->busy)
1189 status = -EBUSY;
1190
1191 spin_unlock_irqrestore(&drv_data->lock, flags);
1192
1193 return status;
1194}
1195
1196static inline int destroy_queue(struct driver_data *drv_data)
1197{
1198 int status;
1199
1200 status = stop_queue(drv_data);
1201 if (status != 0)
1202 return status;
1203
1204 destroy_workqueue(drv_data->workqueue);
1205
1206 return 0;
1207}
1208
Michael Hennerichcc2f81a2007-12-04 23:45:13 -08001209static int setup_pin_mux(int action)
1210{
1211
1212 u16 pin_req[] = {P_SPI0_SCK, P_SPI0_MISO, P_SPI0_MOSI, 0};
1213
1214 if (action) {
1215 if (peripheral_request_list(pin_req, DRV_NAME))
1216 return -EFAULT;
1217 } else {
1218 peripheral_free_list(pin_req);
1219 }
1220
1221 return 0;
1222}
1223
Wu, Bryana5f6abd2007-05-06 14:50:34 -07001224static int __init bfin5xx_spi_probe(struct platform_device *pdev)
1225{
1226 struct device *dev = &pdev->dev;
1227 struct bfin5xx_spi_master *platform_info;
1228 struct spi_master *master;
1229 struct driver_data *drv_data = 0;
Bryan Wua32c6912007-12-04 23:45:15 -08001230 struct resource *res;
Wu, Bryana5f6abd2007-05-06 14:50:34 -07001231 int status = 0;
1232
1233 platform_info = dev->platform_data;
1234
1235 /* Allocate master with space for drv_data */
1236 master = spi_alloc_master(dev, sizeof(struct driver_data) + 16);
1237 if (!master) {
1238 dev_err(&pdev->dev, "can not alloc spi_master\n");
1239 return -ENOMEM;
1240 }
Bryan Wu131b17d2007-12-04 23:45:12 -08001241
Michael Hennerichcc2f81a2007-12-04 23:45:13 -08001242 if (setup_pin_mux(1)) {
Bryan Wu131b17d2007-12-04 23:45:12 -08001243 dev_err(&pdev->dev, ": Requesting Peripherals failed\n");
Michael Hennerichcc2f81a2007-12-04 23:45:13 -08001244 goto out_error;
Bryan Wu131b17d2007-12-04 23:45:12 -08001245 }
1246
Wu, Bryana5f6abd2007-05-06 14:50:34 -07001247 drv_data = spi_master_get_devdata(master);
1248 drv_data->master = master;
1249 drv_data->master_info = platform_info;
1250 drv_data->pdev = pdev;
1251
1252 master->bus_num = pdev->id;
1253 master->num_chipselect = platform_info->num_chipselect;
1254 master->cleanup = cleanup;
1255 master->setup = setup;
1256 master->transfer = transfer;
1257
Bryan Wua32c6912007-12-04 23:45:15 -08001258 /* Find and map our resources */
1259 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1260 if (res == NULL) {
1261 dev_err(dev, "Cannot get IORESOURCE_MEM\n");
1262 status = -ENOENT;
1263 goto out_error_get_res;
1264 }
1265
1266 spi_regs_base = (u32) ioremap(res->start, (res->end - res->start)+1);
1267 if (!spi_regs_base) {
1268 dev_err(dev, "Cannot map IO\n");
1269 status = -ENXIO;
1270 goto out_error_ioremap;
1271 }
1272
1273 spi_dma_ch = platform_get_irq(pdev, 0);
1274 if (spi_dma_ch < 0) {
1275 dev_err(dev, "No DMA channel specified\n");
1276 status = -ENOENT;
1277 goto out_error_no_dma_ch;
1278 }
1279
Wu, Bryana5f6abd2007-05-06 14:50:34 -07001280 /* Initial and start queue */
1281 status = init_queue(drv_data);
1282 if (status != 0) {
Bryan Wua32c6912007-12-04 23:45:15 -08001283 dev_err(dev, "problem initializing queue\n");
Wu, Bryana5f6abd2007-05-06 14:50:34 -07001284 goto out_error_queue_alloc;
1285 }
Bryan Wua32c6912007-12-04 23:45:15 -08001286
Wu, Bryana5f6abd2007-05-06 14:50:34 -07001287 status = start_queue(drv_data);
1288 if (status != 0) {
Bryan Wua32c6912007-12-04 23:45:15 -08001289 dev_err(dev, "problem starting queue\n");
Wu, Bryana5f6abd2007-05-06 14:50:34 -07001290 goto out_error_queue_alloc;
1291 }
1292
1293 /* Register with the SPI framework */
1294 platform_set_drvdata(pdev, drv_data);
1295 status = spi_register_master(master);
1296 if (status != 0) {
Bryan Wua32c6912007-12-04 23:45:15 -08001297 dev_err(dev, "problem registering spi master\n");
Wu, Bryana5f6abd2007-05-06 14:50:34 -07001298 goto out_error_queue_alloc;
1299 }
Bryan Wua32c6912007-12-04 23:45:15 -08001300
1301 dev_info(dev, "%s, Version %s, regs_base @ 0x%08x\n",
1302 DRV_DESC, DRV_VERSION, spi_regs_base);
Wu, Bryana5f6abd2007-05-06 14:50:34 -07001303 return status;
1304
Michael Hennerichcc2f81a2007-12-04 23:45:13 -08001305out_error_queue_alloc:
Wu, Bryana5f6abd2007-05-06 14:50:34 -07001306 destroy_queue(drv_data);
Bryan Wua32c6912007-12-04 23:45:15 -08001307out_error_no_dma_ch:
1308 iounmap((void *) spi_regs_base);
1309out_error_ioremap:
1310out_error_get_res:
Michael Hennerichcc2f81a2007-12-04 23:45:13 -08001311out_error:
Wu, Bryana5f6abd2007-05-06 14:50:34 -07001312 spi_master_put(master);
Michael Hennerichcc2f81a2007-12-04 23:45:13 -08001313
Wu, Bryana5f6abd2007-05-06 14:50:34 -07001314 return status;
1315}
1316
1317/* stop hardware and remove the driver */
1318static int __devexit bfin5xx_spi_remove(struct platform_device *pdev)
1319{
1320 struct driver_data *drv_data = platform_get_drvdata(pdev);
1321 int status = 0;
1322
1323 if (!drv_data)
1324 return 0;
1325
1326 /* Remove the queue */
1327 status = destroy_queue(drv_data);
1328 if (status != 0)
1329 return status;
1330
1331 /* Disable the SSP at the peripheral and SOC level */
1332 bfin_spi_disable(drv_data);
1333
1334 /* Release DMA */
1335 if (drv_data->master_info->enable_dma) {
Bryan Wua32c6912007-12-04 23:45:15 -08001336 if (dma_channel_active(spi_dma_ch))
1337 free_dma(spi_dma_ch);
Wu, Bryana5f6abd2007-05-06 14:50:34 -07001338 }
1339
1340 /* Disconnect from the SPI framework */
1341 spi_unregister_master(drv_data->master);
1342
Michael Hennerichcc2f81a2007-12-04 23:45:13 -08001343 setup_pin_mux(0);
1344
Wu, Bryana5f6abd2007-05-06 14:50:34 -07001345 /* Prevent double remove */
1346 platform_set_drvdata(pdev, NULL);
1347
1348 return 0;
1349}
1350
1351#ifdef CONFIG_PM
1352static int bfin5xx_spi_suspend(struct platform_device *pdev, pm_message_t state)
1353{
1354 struct driver_data *drv_data = platform_get_drvdata(pdev);
1355 int status = 0;
1356
1357 status = stop_queue(drv_data);
1358 if (status != 0)
1359 return status;
1360
1361 /* stop hardware */
1362 bfin_spi_disable(drv_data);
1363
1364 return 0;
1365}
1366
1367static int bfin5xx_spi_resume(struct platform_device *pdev)
1368{
1369 struct driver_data *drv_data = platform_get_drvdata(pdev);
1370 int status = 0;
1371
1372 /* Enable the SPI interface */
1373 bfin_spi_enable(drv_data);
1374
1375 /* Start the queue running */
1376 status = start_queue(drv_data);
1377 if (status != 0) {
1378 dev_err(&pdev->dev, "problem starting queue (%d)\n", status);
1379 return status;
1380 }
1381
1382 return 0;
1383}
1384#else
1385#define bfin5xx_spi_suspend NULL
1386#define bfin5xx_spi_resume NULL
1387#endif /* CONFIG_PM */
1388
David Brownellfc3ba952007-08-30 23:56:24 -07001389MODULE_ALIAS("bfin-spi-master"); /* for platform bus hotplug */
Wu, Bryana5f6abd2007-05-06 14:50:34 -07001390static struct platform_driver bfin5xx_spi_driver = {
David Brownellfc3ba952007-08-30 23:56:24 -07001391 .driver = {
Bryan Wua32c6912007-12-04 23:45:15 -08001392 .name = DRV_NAME,
Bryan Wu88b40362007-05-21 18:32:16 +08001393 .owner = THIS_MODULE,
1394 },
1395 .suspend = bfin5xx_spi_suspend,
1396 .resume = bfin5xx_spi_resume,
1397 .remove = __devexit_p(bfin5xx_spi_remove),
Wu, Bryana5f6abd2007-05-06 14:50:34 -07001398};
1399
1400static int __init bfin5xx_spi_init(void)
1401{
Bryan Wu88b40362007-05-21 18:32:16 +08001402 return platform_driver_probe(&bfin5xx_spi_driver, bfin5xx_spi_probe);
Wu, Bryana5f6abd2007-05-06 14:50:34 -07001403}
Wu, Bryana5f6abd2007-05-06 14:50:34 -07001404module_init(bfin5xx_spi_init);
1405
1406static void __exit bfin5xx_spi_exit(void)
1407{
1408 platform_driver_unregister(&bfin5xx_spi_driver);
1409}
Wu, Bryana5f6abd2007-05-06 14:50:34 -07001410module_exit(bfin5xx_spi_exit);