spi-bfin5xx.c revision 12e17c4267a5b2a5ba77bd53a62388be641534b8
1a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan/*
2131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu * File:	drivers/spi/bfin5xx_spi.c
3131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu * Maintainer:
4131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu *		Bryan Wu <bryan.wu@analog.com>
5131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu * Original Author:
6131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu *		Luke Yang (Analog Devices Inc.)
7a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan *
8131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu * Created:	March. 10th 2006
9131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu * Description:	SPI controller driver for Blackfin BF5xx
10131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu * Bugs:	Enter bugs at http://blackfin.uclinux.org/
11a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan *
12a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan * Modified:
13a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan *	March 10, 2006  bfin5xx_spi.c Created. (Luke Yang)
14a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan *      August 7, 2006  added full duplex mode (Axel Weiss & Luke Yang)
15131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu *      July  17, 2007  add support for BF54x SPI0 controller (Bryan Wu)
16a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu *      July  30, 2007  add platfrom_resource interface to support multi-port
17a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu *                      SPI controller (Bryan Wu)
18a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan *
19131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu * Copyright 2004-2007 Analog Devices Inc.
20a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan *
21a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan * This program is free software ;  you can redistribute it and/or modify
22a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan * it under the terms of the GNU General Public License as published by
23a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan * the Free Software Foundation ;  either version 2, or (at your option)
24a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan * any later version.
25a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan *
26a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan * This program is distributed in the hope that it will be useful,
27a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan * but WITHOUT ANY WARRANTY ;  without even the implied warranty of
28a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
29a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan * GNU General Public License for more details.
30a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan *
31a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan * You should have received a copy of the GNU General Public License
32a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan * along with this program ;  see the file COPYING.
33a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan * If not, write to the Free Software Foundation,
34a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
35a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan */
36a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
37a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#include <linux/init.h>
38a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#include <linux/module.h>
39131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu#include <linux/delay.h>
40a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#include <linux/device.h>
41131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu#include <linux/io.h>
42a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#include <linux/ioport.h>
43131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu#include <linux/irq.h>
44a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#include <linux/errno.h>
45a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#include <linux/interrupt.h>
46a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#include <linux/platform_device.h>
47a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#include <linux/dma-mapping.h>
48a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#include <linux/spi/spi.h>
49a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#include <linux/workqueue.h>
50a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
51a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#include <asm/dma.h>
52131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu#include <asm/portmux.h>
53a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#include <asm/bfin5xx_spi.h>
54a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
55a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu#define DRV_NAME	"bfin-spi"
56a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu#define DRV_AUTHOR	"Bryan Wu, Luke Yang"
57a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu#define DRV_DESC	"Blackfin BF5xx on-chip SPI Contoller Driver"
58a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu#define DRV_VERSION	"1.0"
59a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu
60a32c691d7cf5c37af753255ef4843b18a31935b9Bryan WuMODULE_AUTHOR(DRV_AUTHOR);
61a32c691d7cf5c37af753255ef4843b18a31935b9Bryan WuMODULE_DESCRIPTION(DRV_DESC);
62a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, BryanMODULE_LICENSE("GPL");
63a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
64a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#define IS_DMA_ALIGNED(x) (((u32)(x)&0x07)==0)
65a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
66a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wustatic u32 spi_dma_ch;
67a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wustatic u32 spi_regs_base;
68a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu
69a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#define DEFINE_SPI_REG(reg, off) \
70a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic inline u16 read_##reg(void) \
71a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu	{ return bfin_read16(spi_regs_base + off); } \
72a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic inline void write_##reg(u16 v) \
73a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu	{bfin_write16(spi_regs_base + off, v); }
74a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
75a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, BryanDEFINE_SPI_REG(CTRL, 0x00)
76a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, BryanDEFINE_SPI_REG(FLAG, 0x04)
77a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, BryanDEFINE_SPI_REG(STAT, 0x08)
78a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, BryanDEFINE_SPI_REG(TDBR, 0x0C)
79a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, BryanDEFINE_SPI_REG(RDBR, 0x10)
80a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, BryanDEFINE_SPI_REG(BAUD, 0x14)
81a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, BryanDEFINE_SPI_REG(SHAW, 0x18)
82a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#define START_STATE ((void*)0)
83a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#define RUNNING_STATE ((void*)1)
84a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#define DONE_STATE ((void*)2)
85a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#define ERROR_STATE ((void*)-1)
86a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#define QUEUE_RUNNING 0
87a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#define QUEUE_STOPPED 1
88a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanint dma_requested;
89a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
90a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstruct driver_data {
91a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Driver model hookup */
92a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct platform_device *pdev;
93a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
94a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* SPI framework hookup */
95a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct spi_master *master;
96a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
97a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* BFIN hookup */
98a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct bfin5xx_spi_master *master_info;
99a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
100a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Driver message queue */
101a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct workqueue_struct *workqueue;
102a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct work_struct pump_messages;
103a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	spinlock_t lock;
104a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct list_head queue;
105a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	int busy;
106a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	int run;
107a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
108a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Message Transfer pump */
109a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct tasklet_struct pump_transfers;
110a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
111a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Current message transfer state info */
112a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct spi_message *cur_msg;
113a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct spi_transfer *cur_transfer;
114a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct chip_data *cur_chip;
115a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	size_t len_in_bytes;
116a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	size_t len;
117a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	void *tx;
118a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	void *tx_end;
119a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	void *rx;
120a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	void *rx_end;
121a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	int dma_mapped;
122a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	dma_addr_t rx_dma;
123a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	dma_addr_t tx_dma;
124a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	size_t rx_map_len;
125a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	size_t tx_map_len;
126a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	u8 n_bytes;
127fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu	int cs_change;
128a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	void (*write) (struct driver_data *);
129a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	void (*read) (struct driver_data *);
130a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	void (*duplex) (struct driver_data *);
131a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan};
132a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
133a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstruct chip_data {
134a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	u16 ctl_reg;
135a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	u16 baud;
136a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	u16 flag;
137a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
138a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	u8 chip_select_num;
139a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	u8 n_bytes;
14088b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu	u8 width;		/* 0 or 1 */
141a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	u8 enable_dma;
142a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	u8 bits_per_word;	/* 8 or 16 */
143a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	u8 cs_change_per_word;
144a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	u8 cs_chg_udelay;
145a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	void (*write) (struct driver_data *);
146a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	void (*read) (struct driver_data *);
147a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	void (*duplex) (struct driver_data *);
148a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan};
149a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
15088b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wustatic void bfin_spi_enable(struct driver_data *drv_data)
151a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
152a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	u16 cr;
153a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
154a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	cr = read_CTRL();
155a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	write_CTRL(cr | BIT_CTL_ENABLE);
156a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
157a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
15888b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wustatic void bfin_spi_disable(struct driver_data *drv_data)
159a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
160a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	u16 cr;
161a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
162a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	cr = read_CTRL();
163a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	write_CTRL(cr & (~BIT_CTL_ENABLE));
164a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
165a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
166a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan/* Caculate the SPI_BAUD register value based on input HZ */
167a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic u16 hz_to_spi_baud(u32 speed_hz)
168a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
169a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	u_long sclk = get_sclk();
170a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	u16 spi_baud = (sclk / (2 * speed_hz));
171a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
172a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if ((sclk % (2 * speed_hz)) > 0)
173a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		spi_baud++;
174a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
175a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	return spi_baud;
176a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
177a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
178a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic int flush(struct driver_data *drv_data)
179a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
180a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	unsigned long limit = loops_per_jiffy << 1;
181a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
182a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* wait for stop and clear stat */
183a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	while (!(read_STAT() & BIT_STAT_SPIF) && limit--)
184a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		continue;
185a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
186a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	write_STAT(BIT_STAT_CLR);
187a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
188a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	return limit;
189a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
190a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
191fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu/* Chip select operation functions for cs_change flag */
192fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wustatic void cs_active(struct chip_data *chip)
193fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu{
194fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu	u16 flag = read_FLAG();
195fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu
196fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu	flag |= chip->flag;
197fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu	flag &= ~(chip->flag << 8);
198fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu
199fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu	write_FLAG(flag);
200fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu}
201fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu
202fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wustatic void cs_deactive(struct chip_data *chip)
203fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu{
204fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu	u16 flag = read_FLAG();
205fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu
206fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu	flag |= (chip->flag << 8);
207fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu
208fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu	write_FLAG(flag);
209fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu}
210fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu
2117c4ef09449ca382da2e39b93ca9d03e3dbd5c17cSonic Zhang#define MAX_SPI_SSEL	7
2125fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu
213a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan/* stop controller and re-config current chip*/
2145fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wustatic int restore_state(struct driver_data *drv_data)
215a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
216a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct chip_data *chip = drv_data->cur_chip;
2175fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu	int ret = 0;
21812e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang
219a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Clear status and disable clock */
220a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	write_STAT(BIT_STAT_CLR);
221a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	bfin_spi_disable(drv_data);
22288b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu	dev_dbg(&drv_data->pdev->dev, "restoring spi ctl state\n");
223a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
2245fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu	/* Load the registers */
2255fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu	write_CTRL(chip->ctl_reg);
2265fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu	write_BAUD(chip->baud);
227fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu	cs_active(chip);
2285fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu
2295fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu	if (ret)
2305fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu		dev_dbg(&drv_data->pdev->dev,
2315fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu			": request chip select number %d failed\n",
2325fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu			chip->chip_select_num);
2335fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu
2345fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu	return ret;
235a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
236a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
237a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan/* used to kick off transfer in rx mode */
238a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic unsigned short dummy_read(void)
239a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
240a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	unsigned short tmp;
241a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	tmp = read_RDBR();
242a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	return tmp;
243a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
244a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
245a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic void null_writer(struct driver_data *drv_data)
246a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
247a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	u8 n_bytes = drv_data->n_bytes;
248a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
249a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	while (drv_data->tx < drv_data->tx_end) {
250a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		write_TDBR(0);
251a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		while ((read_STAT() & BIT_STAT_TXS))
252a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			continue;
253a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->tx += n_bytes;
254a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
255a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
256a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
257a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic void null_reader(struct driver_data *drv_data)
258a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
259a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	u8 n_bytes = drv_data->n_bytes;
260a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	dummy_read();
261a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
262a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	while (drv_data->rx < drv_data->rx_end) {
263a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		while (!(read_STAT() & BIT_STAT_RXS))
264a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			continue;
265a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		dummy_read();
266a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->rx += n_bytes;
267a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
268a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
269a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
270a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic void u8_writer(struct driver_data *drv_data)
271a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
272131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu	dev_dbg(&drv_data->pdev->dev,
27388b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu		"cr8-s is 0x%x\n", read_STAT());
274a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	while (drv_data->tx < drv_data->tx_end) {
275a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		write_TDBR(*(u8 *) (drv_data->tx));
276a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		while (read_STAT() & BIT_STAT_TXS)
277a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			continue;
278a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		++drv_data->tx;
279a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
280a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
281a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* poll for SPI completion before returning */
282a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	while (!(read_STAT() & BIT_STAT_SPIF))
283a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		continue;
284a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
285a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
286a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic void u8_cs_chg_writer(struct driver_data *drv_data)
287a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
288a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct chip_data *chip = drv_data->cur_chip;
289a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
290a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	while (drv_data->tx < drv_data->tx_end) {
291fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu		cs_active(chip);
292a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
293a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		write_TDBR(*(u8 *) (drv_data->tx));
294a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		while (read_STAT() & BIT_STAT_TXS)
295a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			continue;
296a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		while (!(read_STAT() & BIT_STAT_SPIF))
297a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			continue;
298fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu		cs_deactive(chip);
2995fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu
300a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		if (chip->cs_chg_udelay)
301a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			udelay(chip->cs_chg_udelay);
302a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		++drv_data->tx;
303a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
304fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu	cs_deactive(chip);
3055fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu
306a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
307a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
308a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic void u8_reader(struct driver_data *drv_data)
309a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
310131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu	dev_dbg(&drv_data->pdev->dev,
31188b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu		"cr-8 is 0x%x\n", read_STAT());
312a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
313a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* clear TDBR buffer before read(else it will be shifted out) */
314a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	write_TDBR(0xFFFF);
315a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
316a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	dummy_read();
317a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	while (drv_data->rx < drv_data->rx_end - 1) {
318a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		while (!(read_STAT() & BIT_STAT_RXS))
319a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			continue;
320a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		*(u8 *) (drv_data->rx) = read_RDBR();
321a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		++drv_data->rx;
322a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
323a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
324a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	while (!(read_STAT() & BIT_STAT_RXS))
325a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		continue;
326a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	*(u8 *) (drv_data->rx) = read_SHAW();
327a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	++drv_data->rx;
328a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
329a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
330a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic void u8_cs_chg_reader(struct driver_data *drv_data)
331a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
332a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct chip_data *chip = drv_data->cur_chip;
333a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
334a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	while (drv_data->rx < drv_data->rx_end) {
335fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu		cs_active(chip);
336a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
337a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		read_RDBR();	/* kick off */
338a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		while (!(read_STAT() & BIT_STAT_RXS))
339a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			continue;
340a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		while (!(read_STAT() & BIT_STAT_SPIF))
341a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			continue;
342a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		*(u8 *) (drv_data->rx) = read_SHAW();
343fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu		cs_deactive(chip);
3445fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu
345a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		if (chip->cs_chg_udelay)
346a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			udelay(chip->cs_chg_udelay);
347a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		++drv_data->rx;
348a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
349fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu	cs_deactive(chip);
3505fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu
351a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
352a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
353a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic void u8_duplex(struct driver_data *drv_data)
354a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
355a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* in duplex mode, clk is triggered by writing of TDBR */
356a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	while (drv_data->rx < drv_data->rx_end) {
357a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		write_TDBR(*(u8 *) (drv_data->tx));
358a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		while (!(read_STAT() & BIT_STAT_SPIF))
359a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			continue;
360a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		while (!(read_STAT() & BIT_STAT_RXS))
361a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			continue;
362a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		*(u8 *) (drv_data->rx) = read_RDBR();
363a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		++drv_data->rx;
364a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		++drv_data->tx;
365a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
366a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
367a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
368a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic void u8_cs_chg_duplex(struct driver_data *drv_data)
369a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
370a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct chip_data *chip = drv_data->cur_chip;
371a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
372a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	while (drv_data->rx < drv_data->rx_end) {
373fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu		cs_active(chip);
3745fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu
375a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
376a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		write_TDBR(*(u8 *) (drv_data->tx));
377a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		while (!(read_STAT() & BIT_STAT_SPIF))
378a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			continue;
379a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		while (!(read_STAT() & BIT_STAT_RXS))
380a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			continue;
381a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		*(u8 *) (drv_data->rx) = read_RDBR();
382fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu		cs_deactive(chip);
3835fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu
384a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		if (chip->cs_chg_udelay)
385a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			udelay(chip->cs_chg_udelay);
386a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		++drv_data->rx;
387a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		++drv_data->tx;
388a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
389fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu	cs_deactive(chip);
390a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
391a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
392a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic void u16_writer(struct driver_data *drv_data)
393a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
394131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu	dev_dbg(&drv_data->pdev->dev,
39588b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu		"cr16 is 0x%x\n", read_STAT());
39688b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu
397a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	while (drv_data->tx < drv_data->tx_end) {
398a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		write_TDBR(*(u16 *) (drv_data->tx));
399a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		while ((read_STAT() & BIT_STAT_TXS))
400a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			continue;
401a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->tx += 2;
402a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
403a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
404a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* poll for SPI completion before returning */
405a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	while (!(read_STAT() & BIT_STAT_SPIF))
406a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		continue;
407a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
408a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
409a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic void u16_cs_chg_writer(struct driver_data *drv_data)
410a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
411a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct chip_data *chip = drv_data->cur_chip;
412a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
413a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	while (drv_data->tx < drv_data->tx_end) {
414fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu		cs_active(chip);
415a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
416a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		write_TDBR(*(u16 *) (drv_data->tx));
417a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		while ((read_STAT() & BIT_STAT_TXS))
418a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			continue;
419a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		while (!(read_STAT() & BIT_STAT_SPIF))
420a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			continue;
421fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu		cs_deactive(chip);
4225fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu
423a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		if (chip->cs_chg_udelay)
424a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			udelay(chip->cs_chg_udelay);
425a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->tx += 2;
426a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
427fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu	cs_deactive(chip);
428a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
429a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
430a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic void u16_reader(struct driver_data *drv_data)
431a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
43288b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu	dev_dbg(&drv_data->pdev->dev,
43388b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu		"cr-16 is 0x%x\n", read_STAT());
434a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	dummy_read();
435a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
436a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	while (drv_data->rx < (drv_data->rx_end - 2)) {
437a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		while (!(read_STAT() & BIT_STAT_RXS))
438a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			continue;
439a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		*(u16 *) (drv_data->rx) = read_RDBR();
440a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->rx += 2;
441a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
442a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
443a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	while (!(read_STAT() & BIT_STAT_RXS))
444a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		continue;
445a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	*(u16 *) (drv_data->rx) = read_SHAW();
446a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->rx += 2;
447a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
448a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
449a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic void u16_cs_chg_reader(struct driver_data *drv_data)
450a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
451a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct chip_data *chip = drv_data->cur_chip;
452a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
453a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	while (drv_data->rx < drv_data->rx_end) {
454fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu		cs_active(chip);
455a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
456a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		read_RDBR();	/* kick off */
457a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		while (!(read_STAT() & BIT_STAT_RXS))
458a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			continue;
459a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		while (!(read_STAT() & BIT_STAT_SPIF))
460a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			continue;
461a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		*(u16 *) (drv_data->rx) = read_SHAW();
462fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu		cs_deactive(chip);
4635fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu
464a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		if (chip->cs_chg_udelay)
465a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			udelay(chip->cs_chg_udelay);
466a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->rx += 2;
467a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
468fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu	cs_deactive(chip);
469a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
470a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
471a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic void u16_duplex(struct driver_data *drv_data)
472a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
473a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* in duplex mode, clk is triggered by writing of TDBR */
474a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	while (drv_data->tx < drv_data->tx_end) {
475a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		write_TDBR(*(u16 *) (drv_data->tx));
476a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		while (!(read_STAT() & BIT_STAT_SPIF))
477a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			continue;
478a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		while (!(read_STAT() & BIT_STAT_RXS))
479a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			continue;
480a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		*(u16 *) (drv_data->rx) = read_RDBR();
481a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->rx += 2;
482a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->tx += 2;
483a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
484a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
485a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
486a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic void u16_cs_chg_duplex(struct driver_data *drv_data)
487a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
488a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct chip_data *chip = drv_data->cur_chip;
489a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
490a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	while (drv_data->tx < drv_data->tx_end) {
491fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu		cs_active(chip);
492a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
493a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		write_TDBR(*(u16 *) (drv_data->tx));
494a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		while (!(read_STAT() & BIT_STAT_SPIF))
495a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			continue;
496a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		while (!(read_STAT() & BIT_STAT_RXS))
497a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			continue;
498a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		*(u16 *) (drv_data->rx) = read_RDBR();
499fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu		cs_deactive(chip);
5005fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu
501a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		if (chip->cs_chg_udelay)
502a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			udelay(chip->cs_chg_udelay);
503a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->rx += 2;
504a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->tx += 2;
505a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
506fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu	cs_deactive(chip);
507a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
508a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
509a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan/* test if ther is more transfer to be done */
510a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic void *next_transfer(struct driver_data *drv_data)
511a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
512a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct spi_message *msg = drv_data->cur_msg;
513a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct spi_transfer *trans = drv_data->cur_transfer;
514a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
515a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Move to next transfer */
516a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (trans->transfer_list.next != &msg->transfers) {
517a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->cur_transfer =
518a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		    list_entry(trans->transfer_list.next,
519a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			       struct spi_transfer, transfer_list);
520a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return RUNNING_STATE;
521a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	} else
522a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return DONE_STATE;
523a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
524a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
525a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan/*
526a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan * caller already set message->status;
527a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan * dma and pio irqs are blocked give finished message back
528a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan */
529a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic void giveback(struct driver_data *drv_data)
530a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
531fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu	struct chip_data *chip = drv_data->cur_chip;
532a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct spi_transfer *last_transfer;
533a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	unsigned long flags;
534a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct spi_message *msg;
535a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
536a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	spin_lock_irqsave(&drv_data->lock, flags);
537a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	msg = drv_data->cur_msg;
538a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->cur_msg = NULL;
539a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->cur_transfer = NULL;
540a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->cur_chip = NULL;
541a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	queue_work(drv_data->workqueue, &drv_data->pump_messages);
542a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	spin_unlock_irqrestore(&drv_data->lock, flags);
543a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
544a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	last_transfer = list_entry(msg->transfers.prev,
545a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan				   struct spi_transfer, transfer_list);
546a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
547a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	msg->state = NULL;
548a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
549a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* disable chip select signal. And not stop spi in autobuffer mode */
550a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (drv_data->tx_dma != 0xFFFF) {
551fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu		cs_deactive(chip);
552a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		bfin_spi_disable(drv_data);
553a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
554a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
555fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu	if (!drv_data->cs_change)
556fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu		cs_deactive(chip);
557fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu
558a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (msg->complete)
559a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		msg->complete(msg->context);
560a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
561a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
56288b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wustatic irqreturn_t dma_irq_handler(int irq, void *dev_id)
563a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
564a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct driver_data *drv_data = (struct driver_data *)dev_id;
565a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct spi_message *msg = drv_data->cur_msg;
566fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu	struct chip_data *chip = drv_data->cur_chip;
567a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
56888b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu	dev_dbg(&drv_data->pdev->dev, "in dma_irq_handler\n");
569a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu	clear_dma_irqstat(spi_dma_ch);
570a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
571d6fe89b0630080e2bd6ece20ff7b1b5c2647ed62Bryan Wu	/* Wait for DMA to complete */
572a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu	while (get_dma_curr_irqstat(spi_dma_ch) & DMA_RUN)
573d6fe89b0630080e2bd6ece20ff7b1b5c2647ed62Bryan Wu		continue;
574d6fe89b0630080e2bd6ece20ff7b1b5c2647ed62Bryan Wu
575a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/*
576d6fe89b0630080e2bd6ece20ff7b1b5c2647ed62Bryan Wu	 * wait for the last transaction shifted out.  HRM states:
577d6fe89b0630080e2bd6ece20ff7b1b5c2647ed62Bryan Wu	 * at this point there may still be data in the SPI DMA FIFO waiting
578d6fe89b0630080e2bd6ece20ff7b1b5c2647ed62Bryan Wu	 * to be transmitted ... software needs to poll TXS in the SPI_STAT
579d6fe89b0630080e2bd6ece20ff7b1b5c2647ed62Bryan Wu	 * register until it goes low for 2 successive reads
580a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	 */
581a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (drv_data->tx != NULL) {
582a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu		while ((read_STAT() & TXS) ||
583a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu		       (read_STAT() & TXS))
584a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			continue;
585a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
586a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
587a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu	while (!(read_STAT() & SPIF))
588a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		continue;
589a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
590a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	bfin_spi_disable(drv_data);
591a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
592a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	msg->actual_length += drv_data->len_in_bytes;
593a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
594fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu	if (drv_data->cs_change)
595fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu		cs_deactive(chip);
596fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu
597a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Move to next transfer */
598a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	msg->state = next_transfer(drv_data);
599a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
600a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Schedule transfer tasklet */
601a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	tasklet_schedule(&drv_data->pump_transfers);
602a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
603a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* free the irq handler before next transfer */
60488b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu	dev_dbg(&drv_data->pdev->dev,
60588b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu		"disable dma channel irq%d\n",
606a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu		spi_dma_ch);
607a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu	dma_disable_irq(spi_dma_ch);
608a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
609a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	return IRQ_HANDLED;
610a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
611a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
612a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic void pump_transfers(unsigned long data)
613a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
614a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct driver_data *drv_data = (struct driver_data *)data;
615a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct spi_message *message = NULL;
616a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct spi_transfer *transfer = NULL;
617a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct spi_transfer *previous = NULL;
618a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct chip_data *chip = NULL;
61988b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu	u8 width;
62088b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu	u16 cr, dma_width, dma_config;
621a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	u32 tranf_success = 1;
622a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
623a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Get current state information */
624a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	message = drv_data->cur_msg;
625a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	transfer = drv_data->cur_transfer;
626a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	chip = drv_data->cur_chip;
627a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/*
628a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	 * if msg is error or done, report it back using complete() callback
629a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	 */
630a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
631a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	 /* Handle for abort */
632a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (message->state == ERROR_STATE) {
633a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		message->status = -EIO;
634a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		giveback(drv_data);
635a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return;
636a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
637a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
638a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Handle end of message */
639a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (message->state == DONE_STATE) {
640a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		message->status = 0;
641a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		giveback(drv_data);
642a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return;
643a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
644a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
645a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Delay if requested at end of transfer */
646a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (message->state == RUNNING_STATE) {
647a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		previous = list_entry(transfer->transfer_list.prev,
648a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan				      struct spi_transfer, transfer_list);
649a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		if (previous->delay_usecs)
650a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			udelay(previous->delay_usecs);
651a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
652a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
653a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Setup the transfer state based on the type of transfer */
654a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (flush(drv_data) == 0) {
655a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		dev_err(&drv_data->pdev->dev, "pump_transfers: flush failed\n");
656a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		message->status = -EIO;
657a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		giveback(drv_data);
658a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return;
659a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
660a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
661a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (transfer->tx_buf != NULL) {
662a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->tx = (void *)transfer->tx_buf;
663a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->tx_end = drv_data->tx + transfer->len;
66488b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu		dev_dbg(&drv_data->pdev->dev, "tx_buf is %p, tx_end is %p\n",
66588b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu			transfer->tx_buf, drv_data->tx_end);
666a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	} else {
667a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->tx = NULL;
668a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
669a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
670a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (transfer->rx_buf != NULL) {
671a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->rx = transfer->rx_buf;
672a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->rx_end = drv_data->rx + transfer->len;
67388b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu		dev_dbg(&drv_data->pdev->dev, "rx_buf is %p, rx_end is %p\n",
67488b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu			transfer->rx_buf, drv_data->rx_end);
675a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	} else {
676a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->rx = NULL;
677a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
678a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
679a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->rx_dma = transfer->rx_dma;
680a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->tx_dma = transfer->tx_dma;
681a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->len_in_bytes = transfer->len;
682fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu	drv_data->cs_change = transfer->cs_change;
683a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
684a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	width = chip->width;
685a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (width == CFG_SPI_WORDSIZE16) {
686a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->len = (transfer->len) >> 1;
687a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	} else {
688a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->len = transfer->len;
689a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
690a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->write = drv_data->tx ? chip->write : null_writer;
691a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->read = drv_data->rx ? chip->read : null_reader;
692a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->duplex = chip->duplex ? chip->duplex : null_writer;
693131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu	dev_dbg(&drv_data->pdev->dev, "transfer: ",
694131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu		"drv_data->write is %p, chip->write is %p, null_wr is %p\n",
695131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu		drv_data->write, chip->write, null_writer);
696a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
697a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* speed and width has been set on per message */
698a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	message->state = RUNNING_STATE;
699a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	dma_config = 0;
700a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
701a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* restore spi status for each spi transfer */
702a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (transfer->speed_hz) {
703a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		write_BAUD(hz_to_spi_baud(transfer->speed_hz));
704a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	} else {
705a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		write_BAUD(chip->baud);
706a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
707fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu	cs_active(chip);
708a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
70988b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu	dev_dbg(&drv_data->pdev->dev,
71088b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu		"now pumping a transfer: width is %d, len is %d\n",
71188b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu		width, transfer->len);
712a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
713a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/*
714a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	 * Try to map dma buffer and do a dma transfer if
715a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	 * successful use different way to r/w according to
716a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	 * drv_data->cur_chip->enable_dma
717a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	 */
718a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (drv_data->cur_chip->enable_dma && drv_data->len > 6) {
719a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
720a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		write_STAT(BIT_STAT_CLR);
721a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu		disable_dma(spi_dma_ch);
722a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu		clear_dma_irqstat(spi_dma_ch);
723a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		bfin_spi_disable(drv_data);
724a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
725a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		/* config dma channel */
72688b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu		dev_dbg(&drv_data->pdev->dev, "doing dma transfer\n");
727a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		if (width == CFG_SPI_WORDSIZE16) {
728a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu			set_dma_x_count(spi_dma_ch, drv_data->len);
729a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu			set_dma_x_modify(spi_dma_ch, 2);
730a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			dma_width = WDSIZE_16;
731a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		} else {
732a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu			set_dma_x_count(spi_dma_ch, drv_data->len);
733a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu			set_dma_x_modify(spi_dma_ch, 1);
734a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			dma_width = WDSIZE_8;
735a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		}
736a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
737a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		/* set transfer width,direction. And enable spi */
738a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		cr = (read_CTRL() & (~BIT_CTL_TIMOD));
739a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
740a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		/* dirty hack for autobuffer DMA mode */
741a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		if (drv_data->tx_dma == 0xFFFF) {
74288b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu			dev_dbg(&drv_data->pdev->dev,
74388b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu				"doing autobuffer DMA out.\n");
744a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
745a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			/* no irq in autobuffer mode */
746a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			dma_config =
747a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			    (DMAFLOW_AUTO | RESTART | dma_width | DI_EN);
748a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu			set_dma_config(spi_dma_ch, dma_config);
749a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu			set_dma_start_addr(spi_dma_ch,
750a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu					(unsigned long)drv_data->tx);
751a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu			enable_dma(spi_dma_ch);
752a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			write_CTRL(cr | CFG_SPI_DMAWRITE | (width << 8) |
753a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan				   (CFG_SPI_ENABLE << 14));
754a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
755a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			/* just return here, there can only be one transfer in this mode */
756a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			message->status = 0;
757a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			giveback(drv_data);
758a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			return;
759a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		}
760a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
761a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		/* In dma mode, rx or tx must be NULL in one transfer */
762a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		if (drv_data->rx != NULL) {
763a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			/* set transfer mode, and enable SPI */
76488b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu			dev_dbg(&drv_data->pdev->dev, "doing DMA in.\n");
765a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
766a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			/* disable SPI before write to TDBR */
767a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			write_CTRL(cr & ~BIT_CTL_ENABLE);
768a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
769a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			/* clear tx reg soformer data is not shifted out */
770a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			write_TDBR(0xFF);
771a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
772a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu			set_dma_x_count(spi_dma_ch, drv_data->len);
773a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
774a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			/* start dma */
775a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu			dma_enable_irq(spi_dma_ch);
776a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			dma_config = (WNR | RESTART | dma_width | DI_EN);
777a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu			set_dma_config(spi_dma_ch, dma_config);
778a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu			set_dma_start_addr(spi_dma_ch,
779a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu					(unsigned long)drv_data->rx);
780a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu			enable_dma(spi_dma_ch);
781a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
782a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			cr |=
783a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			    CFG_SPI_DMAREAD | (width << 8) | (CFG_SPI_ENABLE <<
784a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan							      14);
785a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			/* set transfer mode, and enable SPI */
786a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			write_CTRL(cr);
787a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		} else if (drv_data->tx != NULL) {
78888b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu			dev_dbg(&drv_data->pdev->dev, "doing DMA out.\n");
789a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
790a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			/* start dma */
791a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu			dma_enable_irq(spi_dma_ch);
792a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			dma_config = (RESTART | dma_width | DI_EN);
793a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu			set_dma_config(spi_dma_ch, dma_config);
794a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu			set_dma_start_addr(spi_dma_ch,
795a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu					(unsigned long)drv_data->tx);
796a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu			enable_dma(spi_dma_ch);
797a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
798a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			write_CTRL(cr | CFG_SPI_DMAWRITE | (width << 8) |
799a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan				   (CFG_SPI_ENABLE << 14));
800a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
801a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		}
802a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	} else {
803a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		/* IO mode write then read */
80488b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu		dev_dbg(&drv_data->pdev->dev, "doing IO transfer\n");
805a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
806a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		write_STAT(BIT_STAT_CLR);
807a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
808a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		if (drv_data->tx != NULL && drv_data->rx != NULL) {
809a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			/* full duplex mode */
810a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			BUG_ON((drv_data->tx_end - drv_data->tx) !=
811a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			       (drv_data->rx_end - drv_data->rx));
812131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu			cr = (read_CTRL() & (~BIT_CTL_TIMOD));
81388b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu			cr |= CFG_SPI_WRITE | (width << 8) |
81488b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu				(CFG_SPI_ENABLE << 14);
81588b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu			dev_dbg(&drv_data->pdev->dev,
81688b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu				"IO duplex: cr is 0x%x\n", cr);
817a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
818a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			write_CTRL(cr);
819a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
820a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			drv_data->duplex(drv_data);
821a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
822a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			if (drv_data->tx != drv_data->tx_end)
823a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan				tranf_success = 0;
824a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		} else if (drv_data->tx != NULL) {
825a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			/* write only half duplex */
82688b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu			cr = (read_CTRL() & (~BIT_CTL_TIMOD));
82788b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu			cr |= CFG_SPI_WRITE | (width << 8) |
82888b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu				(CFG_SPI_ENABLE << 14);
829131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu			dev_dbg(&drv_data->pdev->dev,
83088b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu				"IO write: cr is 0x%x\n", cr);
831a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
832a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			write_CTRL(cr);
833a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
834a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			drv_data->write(drv_data);
835a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
836a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			if (drv_data->tx != drv_data->tx_end)
837a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan				tranf_success = 0;
838a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		} else if (drv_data->rx != NULL) {
839a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			/* read only half duplex */
84088b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu			cr = (read_CTRL() & (~BIT_CTL_TIMOD));
84188b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu			cr |= CFG_SPI_READ | (width << 8) |
84288b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu				(CFG_SPI_ENABLE << 14);
843131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu			dev_dbg(&drv_data->pdev->dev,
84488b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu				"IO read: cr is 0x%x\n", cr);
845a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
846a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			write_CTRL(cr);
847a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
848a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			drv_data->read(drv_data);
849a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			if (drv_data->rx != drv_data->rx_end)
850a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan				tranf_success = 0;
851a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		}
852a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
853a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		if (!tranf_success) {
854131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu			dev_dbg(&drv_data->pdev->dev,
85588b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu				"IO write error!\n");
856a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			message->state = ERROR_STATE;
857a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		} else {
858a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			/* Update total byte transfered */
859a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			message->actual_length += drv_data->len;
860a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
861fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu			if (drv_data->cs_change)
862fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu				cs_deactive(chip);
863fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu
864a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			/* Move to next transfer of this msg */
865a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			message->state = next_transfer(drv_data);
866a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		}
867a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
868a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		/* Schedule next transfer tasklet */
869a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		tasklet_schedule(&drv_data->pump_transfers);
870a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
871a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
872a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
873a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
874a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan/* pop a msg from queue and kick off real transfer */
875a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic void pump_messages(struct work_struct *work)
876a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
877131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu	struct driver_data *drv_data;
878a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	unsigned long flags;
879a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
880131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu	drv_data = container_of(work, struct driver_data, pump_messages);
881131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu
882a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Lock queue and check for queue work */
883a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	spin_lock_irqsave(&drv_data->lock, flags);
884a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (list_empty(&drv_data->queue) || drv_data->run == QUEUE_STOPPED) {
885a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		/* pumper kicked off but no work to do */
886a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->busy = 0;
887a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		spin_unlock_irqrestore(&drv_data->lock, flags);
888a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return;
889a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
890a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
891a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Make sure we are not already running a message */
892a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (drv_data->cur_msg) {
893a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		spin_unlock_irqrestore(&drv_data->lock, flags);
894a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return;
895a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
896a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
897a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Extract head of queue */
898a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->cur_msg = list_entry(drv_data->queue.next,
899a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan				       struct spi_message, queue);
9005fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu
9015fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu	/* Setup the SSP using the per chip configuration */
9025fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu	drv_data->cur_chip = spi_get_ctldata(drv_data->cur_msg->spi);
9035fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu	if (restore_state(drv_data)) {
9045fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu		spin_unlock_irqrestore(&drv_data->lock, flags);
9055fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu		return;
9065fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu	};
9075fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu
908a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	list_del_init(&drv_data->cur_msg->queue);
909a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
910a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Initial message state */
911a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->cur_msg->state = START_STATE;
912a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->cur_transfer = list_entry(drv_data->cur_msg->transfers.next,
913a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan					    struct spi_transfer, transfer_list);
914a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
9155fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu	dev_dbg(&drv_data->pdev->dev, "got a message to pump, "
9165fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu		"state is set to: baud %d, flag 0x%x, ctl 0x%x\n",
9175fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu		drv_data->cur_chip->baud, drv_data->cur_chip->flag,
9185fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu		drv_data->cur_chip->ctl_reg);
919131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu
920131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu	dev_dbg(&drv_data->pdev->dev,
92188b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu		"the first transfer len is %d\n",
92288b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu		drv_data->cur_transfer->len);
923a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
924a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Mark as busy and launch transfers */
925a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	tasklet_schedule(&drv_data->pump_transfers);
926a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
927a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->busy = 1;
928a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	spin_unlock_irqrestore(&drv_data->lock, flags);
929a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
930a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
931a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan/*
932a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan * got a msg to transfer, queue it in drv_data->queue.
933a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan * And kick off message pumper
934a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan */
935a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic int transfer(struct spi_device *spi, struct spi_message *msg)
936a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
937a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct driver_data *drv_data = spi_master_get_devdata(spi->master);
938a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	unsigned long flags;
939a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
940a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	spin_lock_irqsave(&drv_data->lock, flags);
941a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
942a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (drv_data->run == QUEUE_STOPPED) {
943a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		spin_unlock_irqrestore(&drv_data->lock, flags);
944a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return -ESHUTDOWN;
945a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
946a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
947a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	msg->actual_length = 0;
948a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	msg->status = -EINPROGRESS;
949a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	msg->state = START_STATE;
950a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
95188b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu	dev_dbg(&spi->dev, "adding an msg in transfer() \n");
952a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	list_add_tail(&msg->queue, &drv_data->queue);
953a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
954a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (drv_data->run == QUEUE_RUNNING && !drv_data->busy)
955a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		queue_work(drv_data->workqueue, &drv_data->pump_messages);
956a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
957a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	spin_unlock_irqrestore(&drv_data->lock, flags);
958a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
959a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	return 0;
960a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
961a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
96212e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang#define MAX_SPI_SSEL	7
96312e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang
96412e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhangstatic u16 ssel[3][MAX_SPI_SSEL] = {
96512e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang	{P_SPI0_SSEL1, P_SPI0_SSEL2, P_SPI0_SSEL3,
96612e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang	P_SPI0_SSEL4, P_SPI0_SSEL5,
96712e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang	P_SPI0_SSEL6, P_SPI0_SSEL7},
96812e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang
96912e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang	{P_SPI1_SSEL1, P_SPI1_SSEL2, P_SPI1_SSEL3,
97012e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang	P_SPI1_SSEL4, P_SPI1_SSEL5,
97112e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang	P_SPI1_SSEL6, P_SPI1_SSEL7},
97212e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang
97312e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang	{P_SPI2_SSEL1, P_SPI2_SSEL2, P_SPI2_SSEL3,
97412e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang	P_SPI2_SSEL4, P_SPI2_SSEL5,
97512e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang	P_SPI2_SSEL6, P_SPI2_SSEL7},
97612e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang};
97712e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang
978a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan/* first setup for new devices */
979a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic int setup(struct spi_device *spi)
980a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
981a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct bfin5xx_spi_chip *chip_info = NULL;
982a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct chip_data *chip;
983a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct driver_data *drv_data = spi_master_get_devdata(spi->master);
984a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	u8 spi_flg;
985a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
986a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Abort device setup if requested features are not supported */
987a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (spi->mode & ~(SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST)) {
988a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		dev_err(&spi->dev, "requested mode not fully supported\n");
989a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return -EINVAL;
990a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
991a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
992a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Zero (the default) here means 8 bits */
993a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (!spi->bits_per_word)
994a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		spi->bits_per_word = 8;
995a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
996a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (spi->bits_per_word != 8 && spi->bits_per_word != 16)
997a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return -EINVAL;
998a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
999a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Only alloc (or use chip_info) on first setup */
1000a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	chip = spi_get_ctldata(spi);
1001a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (chip == NULL) {
1002a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);
1003a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		if (!chip)
1004a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			return -ENOMEM;
1005a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1006a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		chip->enable_dma = 0;
1007a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		chip_info = spi->controller_data;
1008a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
1009a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1010a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* chip_info isn't always needed */
1011a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (chip_info) {
10122ed355165ff4ec834a75770f2a15dc87f5e06088Mike Frysinger		/* Make sure people stop trying to set fields via ctl_reg
10132ed355165ff4ec834a75770f2a15dc87f5e06088Mike Frysinger		 * when they should actually be using common SPI framework.
10142ed355165ff4ec834a75770f2a15dc87f5e06088Mike Frysinger		 * Currently we let through: WOM EMISO PSSE GM SZ TIMOD.
10152ed355165ff4ec834a75770f2a15dc87f5e06088Mike Frysinger		 * Not sure if a user actually needs/uses any of these,
10162ed355165ff4ec834a75770f2a15dc87f5e06088Mike Frysinger		 * but let's assume (for now) they do.
10172ed355165ff4ec834a75770f2a15dc87f5e06088Mike Frysinger		 */
10182ed355165ff4ec834a75770f2a15dc87f5e06088Mike Frysinger		if (chip_info->ctl_reg & (SPE|MSTR|CPOL|CPHA|LSBF|SIZE)) {
10192ed355165ff4ec834a75770f2a15dc87f5e06088Mike Frysinger			dev_err(&spi->dev, "do not set bits in ctl_reg "
10202ed355165ff4ec834a75770f2a15dc87f5e06088Mike Frysinger				"that the SPI framework manages\n");
10212ed355165ff4ec834a75770f2a15dc87f5e06088Mike Frysinger			return -EINVAL;
10222ed355165ff4ec834a75770f2a15dc87f5e06088Mike Frysinger		}
10232ed355165ff4ec834a75770f2a15dc87f5e06088Mike Frysinger
1024a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		chip->enable_dma = chip_info->enable_dma != 0
1025a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		    && drv_data->master_info->enable_dma;
1026a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		chip->ctl_reg = chip_info->ctl_reg;
1027a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		chip->bits_per_word = chip_info->bits_per_word;
1028a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		chip->cs_change_per_word = chip_info->cs_change_per_word;
1029a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		chip->cs_chg_udelay = chip_info->cs_chg_udelay;
1030a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
1031a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1032a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* translate common spi framework into our register */
1033a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (spi->mode & SPI_CPOL)
1034a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		chip->ctl_reg |= CPOL;
1035a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (spi->mode & SPI_CPHA)
1036a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		chip->ctl_reg |= CPHA;
1037a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (spi->mode & SPI_LSB_FIRST)
1038a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		chip->ctl_reg |= LSBF;
1039a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* we dont support running in slave mode (yet?) */
1040a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	chip->ctl_reg |= MSTR;
1041a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1042a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/*
1043a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	 * if any one SPI chip is registered and wants DMA, request the
1044a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	 * DMA channel for it
1045a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	 */
1046a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (chip->enable_dma && !dma_requested) {
1047a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		/* register dma irq handler */
1048a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu		if (request_dma(spi_dma_ch, "BF53x_SPI_DMA") < 0) {
104988b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu			dev_dbg(&spi->dev,
105088b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu				"Unable to request BlackFin SPI DMA channel\n");
1051a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			return -ENODEV;
1052a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		}
1053a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu		if (set_dma_callback(spi_dma_ch, (void *)dma_irq_handler,
1054a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu			drv_data) < 0) {
105588b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu			dev_dbg(&spi->dev, "Unable to set dma callback\n");
1056a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			return -EPERM;
1057a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		}
1058a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu		dma_disable_irq(spi_dma_ch);
1059a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		dma_requested = 1;
1060a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
1061a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1062a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/*
1063a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	 * Notice: for blackfin, the speed_hz is the value of register
1064a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	 * SPI_BAUD, not the real baudrate
1065a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	 */
1066a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	chip->baud = hz_to_spi_baud(spi->max_speed_hz);
1067a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	spi_flg = ~(1 << (spi->chip_select));
1068a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	chip->flag = ((u16) spi_flg << 8) | (1 << (spi->chip_select));
1069a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	chip->chip_select_num = spi->chip_select;
1070a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1071a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	switch (chip->bits_per_word) {
1072a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	case 8:
1073a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		chip->n_bytes = 1;
1074a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		chip->width = CFG_SPI_WORDSIZE8;
1075a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		chip->read = chip->cs_change_per_word ?
1076a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			u8_cs_chg_reader : u8_reader;
1077a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		chip->write = chip->cs_change_per_word ?
1078a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			u8_cs_chg_writer : u8_writer;
1079a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		chip->duplex = chip->cs_change_per_word ?
1080a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			u8_cs_chg_duplex : u8_duplex;
1081a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		break;
1082a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1083a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	case 16:
1084a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		chip->n_bytes = 2;
1085a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		chip->width = CFG_SPI_WORDSIZE16;
1086a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		chip->read = chip->cs_change_per_word ?
1087a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			u16_cs_chg_reader : u16_reader;
1088a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		chip->write = chip->cs_change_per_word ?
1089a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			u16_cs_chg_writer : u16_writer;
1090a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		chip->duplex = chip->cs_change_per_word ?
1091a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			u16_cs_chg_duplex : u16_duplex;
1092a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		break;
1093a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1094a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	default:
1095a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		dev_err(&spi->dev, "%d bits_per_word is not supported\n",
1096a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan				chip->bits_per_word);
1097a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		kfree(chip);
1098a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return -ENODEV;
1099a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
1100a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1101898eb71cb17644964c5895fb190e79e3d0c49679Joe Perches	dev_dbg(&spi->dev, "setup spi chip %s, width is %d, dma is %d\n",
1102a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			spi->modalias, chip->width, chip->enable_dma);
110388b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu	dev_dbg(&spi->dev, "ctl_reg is 0x%x, flag_reg is 0x%x\n",
1104a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			chip->ctl_reg, chip->flag);
1105a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1106a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	spi_set_ctldata(spi, chip);
1107a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
110812e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang	dev_dbg(&spi->dev, "chip select number is %d\n", chip->chip_select_num);
110912e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang	if ((chip->chip_select_num > 0)
111012e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang		&& (chip->chip_select_num <= spi->master->num_chipselect))
111112e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang		peripheral_request(ssel[spi->master->bus_num]
111212e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang			[chip->chip_select_num-1], DRV_NAME);
111312e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang
1114a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	return 0;
1115a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
1116a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1117a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan/*
1118a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan * callback for spi framework.
1119a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan * clean driver specific data
1120a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan */
112188b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wustatic void cleanup(struct spi_device *spi)
1122a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
112327bb9e79bcfedc1888d23c3c212c189fa8534fe7Mike Frysinger	struct chip_data *chip = spi_get_ctldata(spi);
1124a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
112512e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang	if ((chip->chip_select_num > 0)
112612e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang		&& (chip->chip_select_num <= spi->master->num_chipselect))
112712e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang		peripheral_free(ssel[spi->master->bus_num]
112812e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang					[chip->chip_select_num-1]);
112912e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang
1130a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	kfree(chip);
1131a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
1132a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1133a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic inline int init_queue(struct driver_data *drv_data)
1134a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
1135a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	INIT_LIST_HEAD(&drv_data->queue);
1136a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	spin_lock_init(&drv_data->lock);
1137a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1138a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->run = QUEUE_STOPPED;
1139a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->busy = 0;
1140a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1141a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* init transfer tasklet */
1142a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	tasklet_init(&drv_data->pump_transfers,
1143a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		     pump_transfers, (unsigned long)drv_data);
1144a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1145a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* init messages workqueue */
1146a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	INIT_WORK(&drv_data->pump_messages, pump_messages);
1147a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->workqueue =
114849dce689ad4ef0fd1f970ef762168e4bd46f69a3Tony Jones	    create_singlethread_workqueue(drv_data->master->dev.parent->bus_id);
1149a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (drv_data->workqueue == NULL)
1150a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return -EBUSY;
1151a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1152a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	return 0;
1153a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
1154a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1155a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic inline int start_queue(struct driver_data *drv_data)
1156a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
1157a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	unsigned long flags;
1158a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1159a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	spin_lock_irqsave(&drv_data->lock, flags);
1160a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1161a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (drv_data->run == QUEUE_RUNNING || drv_data->busy) {
1162a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		spin_unlock_irqrestore(&drv_data->lock, flags);
1163a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return -EBUSY;
1164a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
1165a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1166a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->run = QUEUE_RUNNING;
1167a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->cur_msg = NULL;
1168a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->cur_transfer = NULL;
1169a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->cur_chip = NULL;
1170a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	spin_unlock_irqrestore(&drv_data->lock, flags);
1171a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1172a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	queue_work(drv_data->workqueue, &drv_data->pump_messages);
1173a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1174a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	return 0;
1175a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
1176a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1177a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic inline int stop_queue(struct driver_data *drv_data)
1178a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
1179a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	unsigned long flags;
1180a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	unsigned limit = 500;
1181a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	int status = 0;
1182a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1183a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	spin_lock_irqsave(&drv_data->lock, flags);
1184a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1185a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/*
1186a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	 * This is a bit lame, but is optimized for the common execution path.
1187a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	 * A wait_queue on the drv_data->busy could be used, but then the common
1188a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	 * execution path (pump_messages) would be required to call wake_up or
1189a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	 * friends on every SPI message. Do this instead
1190a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	 */
1191a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->run = QUEUE_STOPPED;
1192a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	while (!list_empty(&drv_data->queue) && drv_data->busy && limit--) {
1193a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		spin_unlock_irqrestore(&drv_data->lock, flags);
1194a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		msleep(10);
1195a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		spin_lock_irqsave(&drv_data->lock, flags);
1196a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
1197a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1198a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (!list_empty(&drv_data->queue) || drv_data->busy)
1199a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		status = -EBUSY;
1200a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1201a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	spin_unlock_irqrestore(&drv_data->lock, flags);
1202a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1203a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	return status;
1204a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
1205a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1206a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic inline int destroy_queue(struct driver_data *drv_data)
1207a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
1208a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	int status;
1209a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1210a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	status = stop_queue(drv_data);
1211a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (status != 0)
1212a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return status;
1213a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1214a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	destroy_workqueue(drv_data->workqueue);
1215a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1216a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	return 0;
1217a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
1218a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
12197c4ef09449ca382da2e39b93ca9d03e3dbd5c17cSonic Zhangstatic int setup_pin_mux(int action, int bus_num)
1220cc2f81a695640dd1c0cf12b35ee303460fa6d0bcMichael Hennerich{
1221cc2f81a695640dd1c0cf12b35ee303460fa6d0bcMichael Hennerich
12227c4ef09449ca382da2e39b93ca9d03e3dbd5c17cSonic Zhang	u16 pin_req[3][4] = {
12237c4ef09449ca382da2e39b93ca9d03e3dbd5c17cSonic Zhang		{P_SPI0_SCK, P_SPI0_MISO, P_SPI0_MOSI, 0},
12247c4ef09449ca382da2e39b93ca9d03e3dbd5c17cSonic Zhang		{P_SPI1_SCK, P_SPI1_MISO, P_SPI1_MOSI, 0},
12257c4ef09449ca382da2e39b93ca9d03e3dbd5c17cSonic Zhang		{P_SPI2_SCK, P_SPI2_MISO, P_SPI2_MOSI, 0},
12267c4ef09449ca382da2e39b93ca9d03e3dbd5c17cSonic Zhang	};
1227cc2f81a695640dd1c0cf12b35ee303460fa6d0bcMichael Hennerich
1228cc2f81a695640dd1c0cf12b35ee303460fa6d0bcMichael Hennerich	if (action) {
12297c4ef09449ca382da2e39b93ca9d03e3dbd5c17cSonic Zhang		if (peripheral_request_list(pin_req[bus_num], DRV_NAME))
1230cc2f81a695640dd1c0cf12b35ee303460fa6d0bcMichael Hennerich			return -EFAULT;
1231cc2f81a695640dd1c0cf12b35ee303460fa6d0bcMichael Hennerich	} else {
12327c4ef09449ca382da2e39b93ca9d03e3dbd5c17cSonic Zhang		peripheral_free_list(pin_req[bus_num]);
1233cc2f81a695640dd1c0cf12b35ee303460fa6d0bcMichael Hennerich	}
1234cc2f81a695640dd1c0cf12b35ee303460fa6d0bcMichael Hennerich
1235cc2f81a695640dd1c0cf12b35ee303460fa6d0bcMichael Hennerich	return 0;
1236cc2f81a695640dd1c0cf12b35ee303460fa6d0bcMichael Hennerich}
1237cc2f81a695640dd1c0cf12b35ee303460fa6d0bcMichael Hennerich
1238a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic int __init bfin5xx_spi_probe(struct platform_device *pdev)
1239a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
1240a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct device *dev = &pdev->dev;
1241a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct bfin5xx_spi_master *platform_info;
1242a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct spi_master *master;
1243a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct driver_data *drv_data = 0;
1244a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu	struct resource *res;
1245a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	int status = 0;
1246a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1247a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	platform_info = dev->platform_data;
1248a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1249a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Allocate master with space for drv_data */
1250a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	master = spi_alloc_master(dev, sizeof(struct driver_data) + 16);
1251a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (!master) {
1252a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		dev_err(&pdev->dev, "can not alloc spi_master\n");
1253a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return -ENOMEM;
1254a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
1255131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu
1256a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data = spi_master_get_devdata(master);
1257a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->master = master;
1258a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->master_info = platform_info;
1259a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->pdev = pdev;
1260a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1261a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	master->bus_num = pdev->id;
1262a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	master->num_chipselect = platform_info->num_chipselect;
1263a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	master->cleanup = cleanup;
1264a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	master->setup = setup;
1265a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	master->transfer = transfer;
1266a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1267a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu	/* Find and map our resources */
1268a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1269a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu	if (res == NULL) {
1270a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu		dev_err(dev, "Cannot get IORESOURCE_MEM\n");
1271a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu		status = -ENOENT;
1272a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu		goto out_error_get_res;
1273a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu	}
1274a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu
1275a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu	spi_regs_base = (u32) ioremap(res->start, (res->end - res->start)+1);
1276a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu	if (!spi_regs_base) {
1277a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu		dev_err(dev, "Cannot map IO\n");
1278a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu		status = -ENXIO;
1279a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu		goto out_error_ioremap;
1280a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu	}
1281a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu
1282a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu	spi_dma_ch = platform_get_irq(pdev, 0);
1283a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu	if (spi_dma_ch < 0) {
1284a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu		dev_err(dev, "No DMA channel specified\n");
1285a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu		status = -ENOENT;
1286a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu		goto out_error_no_dma_ch;
1287a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu	}
1288a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu
1289a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Initial and start queue */
1290a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	status = init_queue(drv_data);
1291a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (status != 0) {
1292a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu		dev_err(dev, "problem initializing queue\n");
1293a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		goto out_error_queue_alloc;
1294a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
1295a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu
1296a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	status = start_queue(drv_data);
1297a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (status != 0) {
1298a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu		dev_err(dev, "problem starting queue\n");
1299a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		goto out_error_queue_alloc;
1300a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
1301a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1302a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Register with the SPI framework */
1303a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	platform_set_drvdata(pdev, drv_data);
1304a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	status = spi_register_master(master);
1305a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (status != 0) {
1306a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu		dev_err(dev, "problem registering spi master\n");
1307a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		goto out_error_queue_alloc;
1308a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
1309a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu
13107c4ef09449ca382da2e39b93ca9d03e3dbd5c17cSonic Zhang	if (setup_pin_mux(1, master->bus_num)) {
13117c4ef09449ca382da2e39b93ca9d03e3dbd5c17cSonic Zhang		dev_err(&pdev->dev, ": Requesting Peripherals failed\n");
13127c4ef09449ca382da2e39b93ca9d03e3dbd5c17cSonic Zhang		goto out_error;
13137c4ef09449ca382da2e39b93ca9d03e3dbd5c17cSonic Zhang	}
13147c4ef09449ca382da2e39b93ca9d03e3dbd5c17cSonic Zhang
1315a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu	dev_info(dev, "%s, Version %s, regs_base @ 0x%08x\n",
1316a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu		DRV_DESC, DRV_VERSION, spi_regs_base);
1317a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	return status;
1318a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1319cc2f81a695640dd1c0cf12b35ee303460fa6d0bcMichael Hennerichout_error_queue_alloc:
1320a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	destroy_queue(drv_data);
1321a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wuout_error_no_dma_ch:
1322a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu	iounmap((void *) spi_regs_base);
1323a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wuout_error_ioremap:
1324a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wuout_error_get_res:
1325cc2f81a695640dd1c0cf12b35ee303460fa6d0bcMichael Hennerichout_error:
1326a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	spi_master_put(master);
1327cc2f81a695640dd1c0cf12b35ee303460fa6d0bcMichael Hennerich
1328a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	return status;
1329a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
1330a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1331a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan/* stop hardware and remove the driver */
1332a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic int __devexit bfin5xx_spi_remove(struct platform_device *pdev)
1333a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
1334a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct driver_data *drv_data = platform_get_drvdata(pdev);
1335a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	int status = 0;
1336a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1337a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (!drv_data)
1338a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return 0;
1339a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1340a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Remove the queue */
1341a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	status = destroy_queue(drv_data);
1342a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (status != 0)
1343a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return status;
1344a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1345a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Disable the SSP at the peripheral and SOC level */
1346a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	bfin_spi_disable(drv_data);
1347a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1348a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Release DMA */
1349a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (drv_data->master_info->enable_dma) {
1350a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu		if (dma_channel_active(spi_dma_ch))
1351a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu			free_dma(spi_dma_ch);
1352a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
1353a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1354a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Disconnect from the SPI framework */
1355a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	spi_unregister_master(drv_data->master);
1356a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
13577c4ef09449ca382da2e39b93ca9d03e3dbd5c17cSonic Zhang	setup_pin_mux(0, drv_data->master->bus_num);
1358cc2f81a695640dd1c0cf12b35ee303460fa6d0bcMichael Hennerich
1359a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Prevent double remove */
1360a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	platform_set_drvdata(pdev, NULL);
1361a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1362a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	return 0;
1363a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
1364a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1365a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#ifdef CONFIG_PM
1366a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic int bfin5xx_spi_suspend(struct platform_device *pdev, pm_message_t state)
1367a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
1368a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct driver_data *drv_data = platform_get_drvdata(pdev);
1369a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	int status = 0;
1370a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1371a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	status = stop_queue(drv_data);
1372a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (status != 0)
1373a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return status;
1374a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1375a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* stop hardware */
1376a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	bfin_spi_disable(drv_data);
1377a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1378a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	return 0;
1379a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
1380a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1381a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic int bfin5xx_spi_resume(struct platform_device *pdev)
1382a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
1383a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct driver_data *drv_data = platform_get_drvdata(pdev);
1384a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	int status = 0;
1385a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1386a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Enable the SPI interface */
1387a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	bfin_spi_enable(drv_data);
1388a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1389a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Start the queue running */
1390a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	status = start_queue(drv_data);
1391a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (status != 0) {
1392a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		dev_err(&pdev->dev, "problem starting queue (%d)\n", status);
1393a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return status;
1394a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
1395a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1396a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	return 0;
1397a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
1398a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#else
1399a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#define bfin5xx_spi_suspend NULL
1400a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#define bfin5xx_spi_resume NULL
1401a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#endif				/* CONFIG_PM */
1402a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1403fc3ba9525b50ea0d1670357ece21ebedcee507aeDavid BrownellMODULE_ALIAS("bfin-spi-master");	/* for platform bus hotplug */
1404a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic struct platform_driver bfin5xx_spi_driver = {
1405fc3ba9525b50ea0d1670357ece21ebedcee507aeDavid Brownell	.driver	= {
1406a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu		.name	= DRV_NAME,
140788b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu		.owner	= THIS_MODULE,
140888b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu	},
140988b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu	.suspend	= bfin5xx_spi_suspend,
141088b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu	.resume		= bfin5xx_spi_resume,
141188b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu	.remove		= __devexit_p(bfin5xx_spi_remove),
1412a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan};
1413a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1414a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic int __init bfin5xx_spi_init(void)
1415a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
141688b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu	return platform_driver_probe(&bfin5xx_spi_driver, bfin5xx_spi_probe);
1417a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
1418a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanmodule_init(bfin5xx_spi_init);
1419a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1420a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic void __exit bfin5xx_spi_exit(void)
1421a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
1422a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	platform_driver_unregister(&bfin5xx_spi_driver);
1423a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
1424a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanmodule_exit(bfin5xx_spi_exit);
1425