spi-bfin5xx.c revision d24bd1d0dc850e7aa68c27ec288eb699d41a5916
1a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan/*
226fdc1f0df22dd14fd4161ccb2fad94a3a938c48Mike Frysinger * Blackfin On-Chip SPI Driver
3a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan *
4131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu * Copyright 2004-2007 Analog Devices Inc.
5a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan *
626fdc1f0df22dd14fd4161ccb2fad94a3a938c48Mike Frysinger * Enter bugs at http://blackfin.uclinux.org/
7a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan *
826fdc1f0df22dd14fd4161ccb2fad94a3a938c48Mike Frysinger * Licensed under the GPL-2 or later.
9a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan */
10a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
11a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#include <linux/init.h>
12a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#include <linux/module.h>
13131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu#include <linux/delay.h>
14a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#include <linux/device.h>
15131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu#include <linux/io.h>
16a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#include <linux/ioport.h>
17131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu#include <linux/irq.h>
18a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#include <linux/errno.h>
19a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#include <linux/interrupt.h>
20a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#include <linux/platform_device.h>
21a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#include <linux/dma-mapping.h>
22a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#include <linux/spi/spi.h>
23a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#include <linux/workqueue.h>
24a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
25a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#include <asm/dma.h>
26131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu#include <asm/portmux.h>
27a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#include <asm/bfin5xx_spi.h>
288cf5858c51f88208fe56b195251ab4f21265386cVitja Makarov#include <asm/cacheflush.h>
298cf5858c51f88208fe56b195251ab4f21265386cVitja Makarov
30a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu#define DRV_NAME	"bfin-spi"
31a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu#define DRV_AUTHOR	"Bryan Wu, Luke Yang"
326b1a80283908e463cbf1d96d48d7b989af0f2b2fWill Newton#define DRV_DESC	"Blackfin BF5xx on-chip SPI Controller Driver"
33a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu#define DRV_VERSION	"1.0"
34a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu
35a32c691d7cf5c37af753255ef4843b18a31935b9Bryan WuMODULE_AUTHOR(DRV_AUTHOR);
36a32c691d7cf5c37af753255ef4843b18a31935b9Bryan WuMODULE_DESCRIPTION(DRV_DESC);
37a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, BryanMODULE_LICENSE("GPL");
38a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
39bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu#define IS_DMA_ALIGNED(x) (((u32)(x)&0x07) == 0)
40a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
41bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu#define START_STATE	((void *)0)
42bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu#define RUNNING_STATE	((void *)1)
43bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu#define DONE_STATE	((void *)2)
44bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu#define ERROR_STATE	((void *)-1)
45bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu#define QUEUE_RUNNING	0
46bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu#define QUEUE_STOPPED	1
47a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
48a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstruct driver_data {
49a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Driver model hookup */
50a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct platform_device *pdev;
51a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
52a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* SPI framework hookup */
53a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct spi_master *master;
54a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
55bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	/* Regs base of SPI controller */
56f452126c2e4b8bbfd8e41ebdf1e734e3bf18f8e9Bryan Wu	void __iomem *regs_base;
57bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu
58003d922618150eaab53936f57ba8a61f2b601486Bryan Wu	/* Pin request list */
59003d922618150eaab53936f57ba8a61f2b601486Bryan Wu	u16 *pin_req;
60003d922618150eaab53936f57ba8a61f2b601486Bryan Wu
61a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* BFIN hookup */
62a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct bfin5xx_spi_master *master_info;
63a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
64a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Driver message queue */
65a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct workqueue_struct *workqueue;
66a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct work_struct pump_messages;
67a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	spinlock_t lock;
68a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct list_head queue;
69a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	int busy;
70a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	int run;
71a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
72a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Message Transfer pump */
73a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct tasklet_struct pump_transfers;
74a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
75a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Current message transfer state info */
76a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct spi_message *cur_msg;
77a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct spi_transfer *cur_transfer;
78a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct chip_data *cur_chip;
79a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	size_t len_in_bytes;
80a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	size_t len;
81a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	void *tx;
82a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	void *tx_end;
83a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	void *rx;
84a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	void *rx_end;
85bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu
86bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	/* DMA stuffs */
87bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	int dma_channel;
88a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	int dma_mapped;
89bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	int dma_requested;
90a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	dma_addr_t rx_dma;
91a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	dma_addr_t tx_dma;
92bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu
93a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	size_t rx_map_len;
94a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	size_t tx_map_len;
95a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	u8 n_bytes;
96fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu	int cs_change;
97a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	void (*write) (struct driver_data *);
98a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	void (*read) (struct driver_data *);
99a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	void (*duplex) (struct driver_data *);
100a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan};
101a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
102a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstruct chip_data {
103a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	u16 ctl_reg;
104a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	u16 baud;
105a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	u16 flag;
106a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
107a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	u8 chip_select_num;
108a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	u8 n_bytes;
10988b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu	u8 width;		/* 0 or 1 */
110a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	u8 enable_dma;
111a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	u8 bits_per_word;	/* 8 or 16 */
112a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	u8 cs_change_per_word;
11362310e51ac10c5e50998240e49a84d2e28377a48Bryan Wu	u16 cs_chg_udelay;	/* Some devices require > 255usec delay */
114a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	void (*write) (struct driver_data *);
115a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	void (*read) (struct driver_data *);
116a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	void (*duplex) (struct driver_data *);
117a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan};
118a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
119bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu#define DEFINE_SPI_REG(reg, off) \
120bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wustatic inline u16 read_##reg(struct driver_data *drv_data) \
121bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	{ return bfin_read16(drv_data->regs_base + off); } \
122bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wustatic inline void write_##reg(struct driver_data *drv_data, u16 v) \
123bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	{ bfin_write16(drv_data->regs_base + off, v); }
124bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu
125bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan WuDEFINE_SPI_REG(CTRL, 0x00)
126bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan WuDEFINE_SPI_REG(FLAG, 0x04)
127bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan WuDEFINE_SPI_REG(STAT, 0x08)
128bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan WuDEFINE_SPI_REG(TDBR, 0x0C)
129bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan WuDEFINE_SPI_REG(RDBR, 0x10)
130bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan WuDEFINE_SPI_REG(BAUD, 0x14)
131bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan WuDEFINE_SPI_REG(SHAW, 0x18)
132bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu
13388b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wustatic void bfin_spi_enable(struct driver_data *drv_data)
134a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
135a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	u16 cr;
136a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
137bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	cr = read_CTRL(drv_data);
138bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	write_CTRL(drv_data, (cr | BIT_CTL_ENABLE));
139a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
140a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
14188b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wustatic void bfin_spi_disable(struct driver_data *drv_data)
142a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
143a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	u16 cr;
144a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
145bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	cr = read_CTRL(drv_data);
146bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	write_CTRL(drv_data, (cr & (~BIT_CTL_ENABLE)));
147a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
148a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
149a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan/* Caculate the SPI_BAUD register value based on input HZ */
150a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic u16 hz_to_spi_baud(u32 speed_hz)
151a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
152a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	u_long sclk = get_sclk();
153a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	u16 spi_baud = (sclk / (2 * speed_hz));
154a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
155a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if ((sclk % (2 * speed_hz)) > 0)
156a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		spi_baud++;
157a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1587513e006c64fbe2f43aef2139c8c1f2b1a9cb6b9Michael Hennerich	if (spi_baud < MIN_SPI_BAUD_VAL)
1597513e006c64fbe2f43aef2139c8c1f2b1a9cb6b9Michael Hennerich		spi_baud = MIN_SPI_BAUD_VAL;
1607513e006c64fbe2f43aef2139c8c1f2b1a9cb6b9Michael Hennerich
161a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	return spi_baud;
162a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
163a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
164a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic int flush(struct driver_data *drv_data)
165a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
166a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	unsigned long limit = loops_per_jiffy << 1;
167a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
168a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* wait for stop and clear stat */
169bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	while (!(read_STAT(drv_data) & BIT_STAT_SPIF) && limit--)
170d8c05008b0e464c94967ed2f20d1d661fca6790eBryan Wu		cpu_relax();
171a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
172bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	write_STAT(drv_data, BIT_STAT_CLR);
173a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
174a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	return limit;
175a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
176a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
177fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu/* Chip select operation functions for cs_change flag */
178bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wustatic void cs_active(struct driver_data *drv_data, struct chip_data *chip)
179fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu{
180bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	u16 flag = read_FLAG(drv_data);
181fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu
182fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu	flag |= chip->flag;
183fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu	flag &= ~(chip->flag << 8);
184fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu
185bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	write_FLAG(drv_data, flag);
186fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu}
187fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu
188bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wustatic void cs_deactive(struct driver_data *drv_data, struct chip_data *chip)
189fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu{
190bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	u16 flag = read_FLAG(drv_data);
191fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu
192fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu	flag |= (chip->flag << 8);
193fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu
194bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	write_FLAG(drv_data, flag);
19562310e51ac10c5e50998240e49a84d2e28377a48Bryan Wu
19662310e51ac10c5e50998240e49a84d2e28377a48Bryan Wu	/* Move delay here for consistency */
19762310e51ac10c5e50998240e49a84d2e28377a48Bryan Wu	if (chip->cs_chg_udelay)
19862310e51ac10c5e50998240e49a84d2e28377a48Bryan Wu		udelay(chip->cs_chg_udelay);
199fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu}
200fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu
2017c4ef09449ca382da2e39b93ca9d03e3dbd5c17cSonic Zhang#define MAX_SPI_SSEL	7
2025fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu
203a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan/* stop controller and re-config current chip*/
2048d20d0a7c470cda37db6765866df6338f51ead0fBryan Wustatic void restore_state(struct driver_data *drv_data)
205a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
206a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct chip_data *chip = drv_data->cur_chip;
20712e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang
208a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Clear status and disable clock */
209bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	write_STAT(drv_data, BIT_STAT_CLR);
210a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	bfin_spi_disable(drv_data);
21188b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu	dev_dbg(&drv_data->pdev->dev, "restoring spi ctl state\n");
212a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
2135fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu	/* Load the registers */
214bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	write_CTRL(drv_data, chip->ctl_reg);
215092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu	write_BAUD(drv_data, chip->baud);
216cc487e732089360727e60f9fdbe3ff6cc4ca3155Sonic Zhang
217cc487e732089360727e60f9fdbe3ff6cc4ca3155Sonic Zhang	bfin_spi_enable(drv_data);
21807612e5f224613020c0ba17ce28e8eac052ef8ceSonic Zhang	cs_active(drv_data, chip);
219a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
220a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
221a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan/* used to kick off transfer in rx mode */
222bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wustatic unsigned short dummy_read(struct driver_data *drv_data)
223a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
224a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	unsigned short tmp;
225bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	tmp = read_RDBR(drv_data);
226a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	return tmp;
227a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
228a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
229a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic void null_writer(struct driver_data *drv_data)
230a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
231a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	u8 n_bytes = drv_data->n_bytes;
232a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
233a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	while (drv_data->tx < drv_data->tx_end) {
234bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		write_TDBR(drv_data, 0);
235bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		while ((read_STAT(drv_data) & BIT_STAT_TXS))
236d8c05008b0e464c94967ed2f20d1d661fca6790eBryan Wu			cpu_relax();
237a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->tx += n_bytes;
238a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
239a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
240a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
241a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic void null_reader(struct driver_data *drv_data)
242a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
243a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	u8 n_bytes = drv_data->n_bytes;
244bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	dummy_read(drv_data);
245a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
246a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	while (drv_data->rx < drv_data->rx_end) {
247bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		while (!(read_STAT(drv_data) & BIT_STAT_RXS))
248d8c05008b0e464c94967ed2f20d1d661fca6790eBryan Wu			cpu_relax();
249bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		dummy_read(drv_data);
250a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->rx += n_bytes;
251a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
252a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
253a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
254a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic void u8_writer(struct driver_data *drv_data)
255a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
256131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu	dev_dbg(&drv_data->pdev->dev,
257bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		"cr8-s is 0x%x\n", read_STAT(drv_data));
258cc487e732089360727e60f9fdbe3ff6cc4ca3155Sonic Zhang
259a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	while (drv_data->tx < drv_data->tx_end) {
260bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		write_TDBR(drv_data, (*(u8 *) (drv_data->tx)));
261bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		while (read_STAT(drv_data) & BIT_STAT_TXS)
262d8c05008b0e464c94967ed2f20d1d661fca6790eBryan Wu			cpu_relax();
263a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		++drv_data->tx;
264a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
26513f3e642b24632d206fe2f6a5ee8b275ea062790Sonic Zhang
26613f3e642b24632d206fe2f6a5ee8b275ea062790Sonic Zhang	/* poll for SPI completion before return */
26713f3e642b24632d206fe2f6a5ee8b275ea062790Sonic Zhang	while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
26813f3e642b24632d206fe2f6a5ee8b275ea062790Sonic Zhang		cpu_relax();
269a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
270a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
271a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic void u8_cs_chg_writer(struct driver_data *drv_data)
272a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
273a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct chip_data *chip = drv_data->cur_chip;
274a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
275a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	while (drv_data->tx < drv_data->tx_end) {
276bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		cs_active(drv_data, chip);
277a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
278bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		write_TDBR(drv_data, (*(u8 *) (drv_data->tx)));
279bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		while (read_STAT(drv_data) & BIT_STAT_TXS)
280d8c05008b0e464c94967ed2f20d1d661fca6790eBryan Wu			cpu_relax();
281e26aa015dd34d5768b80815836ad60e8495e9553Bryan Wu		while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
282e26aa015dd34d5768b80815836ad60e8495e9553Bryan Wu			cpu_relax();
28362310e51ac10c5e50998240e49a84d2e28377a48Bryan Wu
284bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		cs_deactive(drv_data, chip);
2855fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu
286a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		++drv_data->tx;
287a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
288a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
289a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
290a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic void u8_reader(struct driver_data *drv_data)
291a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
292131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu	dev_dbg(&drv_data->pdev->dev,
293bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		"cr-8 is 0x%x\n", read_STAT(drv_data));
294a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
2953f479a65b3f49ee4f058a965e6e33d97ee467b68Sonic Zhang	/* poll for SPI completion before start */
296bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
297d8c05008b0e464c94967ed2f20d1d661fca6790eBryan Wu		cpu_relax();
2983f479a65b3f49ee4f058a965e6e33d97ee467b68Sonic Zhang
299a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* clear TDBR buffer before read(else it will be shifted out) */
300bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	write_TDBR(drv_data, 0xFFFF);
301a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
302bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	dummy_read(drv_data);
303cc487e732089360727e60f9fdbe3ff6cc4ca3155Sonic Zhang
304a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	while (drv_data->rx < drv_data->rx_end - 1) {
305bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		while (!(read_STAT(drv_data) & BIT_STAT_RXS))
306d8c05008b0e464c94967ed2f20d1d661fca6790eBryan Wu			cpu_relax();
307bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		*(u8 *) (drv_data->rx) = read_RDBR(drv_data);
308a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		++drv_data->rx;
309a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
310a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
311bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	while (!(read_STAT(drv_data) & BIT_STAT_RXS))
312d8c05008b0e464c94967ed2f20d1d661fca6790eBryan Wu		cpu_relax();
313bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	*(u8 *) (drv_data->rx) = read_SHAW(drv_data);
314a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	++drv_data->rx;
315a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
316a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
317a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic void u8_cs_chg_reader(struct driver_data *drv_data)
318a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
319a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct chip_data *chip = drv_data->cur_chip;
320a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
321e26aa015dd34d5768b80815836ad60e8495e9553Bryan Wu	while (drv_data->rx < drv_data->rx_end) {
322e26aa015dd34d5768b80815836ad60e8495e9553Bryan Wu		cs_active(drv_data, chip);
323e26aa015dd34d5768b80815836ad60e8495e9553Bryan Wu		read_RDBR(drv_data);	/* kick off */
324a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
325e26aa015dd34d5768b80815836ad60e8495e9553Bryan Wu		while (!(read_STAT(drv_data) & BIT_STAT_RXS))
326e26aa015dd34d5768b80815836ad60e8495e9553Bryan Wu			cpu_relax();
327e26aa015dd34d5768b80815836ad60e8495e9553Bryan Wu		while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
328e26aa015dd34d5768b80815836ad60e8495e9553Bryan Wu			cpu_relax();
329cc487e732089360727e60f9fdbe3ff6cc4ca3155Sonic Zhang
330e26aa015dd34d5768b80815836ad60e8495e9553Bryan Wu		*(u8 *) (drv_data->rx) = read_SHAW(drv_data);
331bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		cs_deactive(drv_data, chip);
3325fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu
333a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		++drv_data->rx;
334a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
335a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
336a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
337a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic void u8_duplex(struct driver_data *drv_data)
338a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
339a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* in duplex mode, clk is triggered by writing of TDBR */
340a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	while (drv_data->rx < drv_data->rx_end) {
341bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		write_TDBR(drv_data, (*(u8 *) (drv_data->tx)));
3424fd432d9c7ac9a14e750d2ab0c91bc151e9af32eBryan Wu		while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
343d8c05008b0e464c94967ed2f20d1d661fca6790eBryan Wu			cpu_relax();
344bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		while (!(read_STAT(drv_data) & BIT_STAT_RXS))
345d8c05008b0e464c94967ed2f20d1d661fca6790eBryan Wu			cpu_relax();
346bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		*(u8 *) (drv_data->rx) = read_RDBR(drv_data);
347a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		++drv_data->rx;
348a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		++drv_data->tx;
349a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
350a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
351a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
352a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic void u8_cs_chg_duplex(struct driver_data *drv_data)
353a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
354a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct chip_data *chip = drv_data->cur_chip;
355a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
356a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	while (drv_data->rx < drv_data->rx_end) {
357bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		cs_active(drv_data, chip);
3585fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu
359bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		write_TDBR(drv_data, (*(u8 *) (drv_data->tx)));
360e26aa015dd34d5768b80815836ad60e8495e9553Bryan Wu
361e26aa015dd34d5768b80815836ad60e8495e9553Bryan Wu		while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
362d8c05008b0e464c94967ed2f20d1d661fca6790eBryan Wu			cpu_relax();
363bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		while (!(read_STAT(drv_data) & BIT_STAT_RXS))
364d8c05008b0e464c94967ed2f20d1d661fca6790eBryan Wu			cpu_relax();
365bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		*(u8 *) (drv_data->rx) = read_RDBR(drv_data);
36662310e51ac10c5e50998240e49a84d2e28377a48Bryan Wu
367bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		cs_deactive(drv_data, chip);
3685fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu
369a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		++drv_data->rx;
370a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		++drv_data->tx;
371a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
372a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
373a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
374a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic void u16_writer(struct driver_data *drv_data)
375a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
376131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu	dev_dbg(&drv_data->pdev->dev,
377bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		"cr16 is 0x%x\n", read_STAT(drv_data));
37888b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu
379a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	while (drv_data->tx < drv_data->tx_end) {
380bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		write_TDBR(drv_data, (*(u16 *) (drv_data->tx)));
381bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		while ((read_STAT(drv_data) & BIT_STAT_TXS))
382d8c05008b0e464c94967ed2f20d1d661fca6790eBryan Wu			cpu_relax();
383a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->tx += 2;
384a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
38513f3e642b24632d206fe2f6a5ee8b275ea062790Sonic Zhang
38613f3e642b24632d206fe2f6a5ee8b275ea062790Sonic Zhang	/* poll for SPI completion before return */
38713f3e642b24632d206fe2f6a5ee8b275ea062790Sonic Zhang	while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
38813f3e642b24632d206fe2f6a5ee8b275ea062790Sonic Zhang		cpu_relax();
389a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
390a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
391a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic void u16_cs_chg_writer(struct driver_data *drv_data)
392a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
393a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct chip_data *chip = drv_data->cur_chip;
394a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
395a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	while (drv_data->tx < drv_data->tx_end) {
396bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		cs_active(drv_data, chip);
397a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
398bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		write_TDBR(drv_data, (*(u16 *) (drv_data->tx)));
399bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		while ((read_STAT(drv_data) & BIT_STAT_TXS))
400d8c05008b0e464c94967ed2f20d1d661fca6790eBryan Wu			cpu_relax();
40113f3e642b24632d206fe2f6a5ee8b275ea062790Sonic Zhang		while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
40213f3e642b24632d206fe2f6a5ee8b275ea062790Sonic Zhang			cpu_relax();
40362310e51ac10c5e50998240e49a84d2e28377a48Bryan Wu
404bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		cs_deactive(drv_data, chip);
4055fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu
406a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->tx += 2;
407a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
408a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
409a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
410a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic void u16_reader(struct driver_data *drv_data)
411a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
41288b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu	dev_dbg(&drv_data->pdev->dev,
413bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		"cr-16 is 0x%x\n", read_STAT(drv_data));
414cc487e732089360727e60f9fdbe3ff6cc4ca3155Sonic Zhang
4153f479a65b3f49ee4f058a965e6e33d97ee467b68Sonic Zhang	/* poll for SPI completion before start */
416bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
417d8c05008b0e464c94967ed2f20d1d661fca6790eBryan Wu		cpu_relax();
4183f479a65b3f49ee4f058a965e6e33d97ee467b68Sonic Zhang
419cc487e732089360727e60f9fdbe3ff6cc4ca3155Sonic Zhang	/* clear TDBR buffer before read(else it will be shifted out) */
420bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	write_TDBR(drv_data, 0xFFFF);
421cc487e732089360727e60f9fdbe3ff6cc4ca3155Sonic Zhang
422bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	dummy_read(drv_data);
423a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
424a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	while (drv_data->rx < (drv_data->rx_end - 2)) {
425bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		while (!(read_STAT(drv_data) & BIT_STAT_RXS))
426d8c05008b0e464c94967ed2f20d1d661fca6790eBryan Wu			cpu_relax();
427bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		*(u16 *) (drv_data->rx) = read_RDBR(drv_data);
428a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->rx += 2;
429a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
430a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
431bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	while (!(read_STAT(drv_data) & BIT_STAT_RXS))
432d8c05008b0e464c94967ed2f20d1d661fca6790eBryan Wu		cpu_relax();
433bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	*(u16 *) (drv_data->rx) = read_SHAW(drv_data);
434a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->rx += 2;
435a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
436a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
437a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic void u16_cs_chg_reader(struct driver_data *drv_data)
438a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
439a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct chip_data *chip = drv_data->cur_chip;
440a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
4413f479a65b3f49ee4f058a965e6e33d97ee467b68Sonic Zhang	/* poll for SPI completion before start */
442bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
443d8c05008b0e464c94967ed2f20d1d661fca6790eBryan Wu		cpu_relax();
4443f479a65b3f49ee4f058a965e6e33d97ee467b68Sonic Zhang
445cc487e732089360727e60f9fdbe3ff6cc4ca3155Sonic Zhang	/* clear TDBR buffer before read(else it will be shifted out) */
446bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	write_TDBR(drv_data, 0xFFFF);
447a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
448bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	cs_active(drv_data, chip);
449bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	dummy_read(drv_data);
450cc487e732089360727e60f9fdbe3ff6cc4ca3155Sonic Zhang
451c3061abb9e95920407288cba143dc1af0babf099Bryan Wu	while (drv_data->rx < drv_data->rx_end - 2) {
452bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		cs_deactive(drv_data, chip);
4535fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu
454bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		while (!(read_STAT(drv_data) & BIT_STAT_RXS))
455d8c05008b0e464c94967ed2f20d1d661fca6790eBryan Wu			cpu_relax();
456bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		cs_active(drv_data, chip);
457bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		*(u16 *) (drv_data->rx) = read_RDBR(drv_data);
458a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->rx += 2;
459a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
460bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	cs_deactive(drv_data, chip);
461cc487e732089360727e60f9fdbe3ff6cc4ca3155Sonic Zhang
462bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	while (!(read_STAT(drv_data) & BIT_STAT_RXS))
463d8c05008b0e464c94967ed2f20d1d661fca6790eBryan Wu		cpu_relax();
464bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	*(u16 *) (drv_data->rx) = read_SHAW(drv_data);
465cc487e732089360727e60f9fdbe3ff6cc4ca3155Sonic Zhang	drv_data->rx += 2;
466a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
467a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
468a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic void u16_duplex(struct driver_data *drv_data)
469a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
470a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* in duplex mode, clk is triggered by writing of TDBR */
471a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	while (drv_data->tx < drv_data->tx_end) {
472bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		write_TDBR(drv_data, (*(u16 *) (drv_data->tx)));
4734fd432d9c7ac9a14e750d2ab0c91bc151e9af32eBryan Wu		while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
474d8c05008b0e464c94967ed2f20d1d661fca6790eBryan Wu			cpu_relax();
475bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		while (!(read_STAT(drv_data) & BIT_STAT_RXS))
476d8c05008b0e464c94967ed2f20d1d661fca6790eBryan Wu			cpu_relax();
477bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		*(u16 *) (drv_data->rx) = read_RDBR(drv_data);
478a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->rx += 2;
479a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->tx += 2;
480a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
481a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
482a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
483a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic void u16_cs_chg_duplex(struct driver_data *drv_data)
484a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
485a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct chip_data *chip = drv_data->cur_chip;
486a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
487a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	while (drv_data->tx < drv_data->tx_end) {
488bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		cs_active(drv_data, chip);
489a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
490bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		write_TDBR(drv_data, (*(u16 *) (drv_data->tx)));
4914fd432d9c7ac9a14e750d2ab0c91bc151e9af32eBryan Wu		while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
492d8c05008b0e464c94967ed2f20d1d661fca6790eBryan Wu			cpu_relax();
493bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		while (!(read_STAT(drv_data) & BIT_STAT_RXS))
494d8c05008b0e464c94967ed2f20d1d661fca6790eBryan Wu			cpu_relax();
495bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		*(u16 *) (drv_data->rx) = read_RDBR(drv_data);
49662310e51ac10c5e50998240e49a84d2e28377a48Bryan Wu
497bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		cs_deactive(drv_data, chip);
4985fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu
499a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->rx += 2;
500a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->tx += 2;
501a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
502a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
503a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
504a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan/* test if ther is more transfer to be done */
505a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic void *next_transfer(struct driver_data *drv_data)
506a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
507a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct spi_message *msg = drv_data->cur_msg;
508a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct spi_transfer *trans = drv_data->cur_transfer;
509a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
510a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Move to next transfer */
511a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (trans->transfer_list.next != &msg->transfers) {
512a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->cur_transfer =
513a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		    list_entry(trans->transfer_list.next,
514a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			       struct spi_transfer, transfer_list);
515a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return RUNNING_STATE;
516a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	} else
517a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return DONE_STATE;
518a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
519a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
520a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan/*
521a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan * caller already set message->status;
522a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan * dma and pio irqs are blocked give finished message back
523a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan */
524a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic void giveback(struct driver_data *drv_data)
525a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
526fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu	struct chip_data *chip = drv_data->cur_chip;
527a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct spi_transfer *last_transfer;
528a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	unsigned long flags;
529a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct spi_message *msg;
530a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
531a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	spin_lock_irqsave(&drv_data->lock, flags);
532a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	msg = drv_data->cur_msg;
533a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->cur_msg = NULL;
534a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->cur_transfer = NULL;
535a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->cur_chip = NULL;
536a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	queue_work(drv_data->workqueue, &drv_data->pump_messages);
537a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	spin_unlock_irqrestore(&drv_data->lock, flags);
538a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
539a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	last_transfer = list_entry(msg->transfers.prev,
540a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan				   struct spi_transfer, transfer_list);
541a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
542a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	msg->state = NULL;
543a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
544a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* disable chip select signal. And not stop spi in autobuffer mode */
545a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (drv_data->tx_dma != 0xFFFF) {
546bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		cs_deactive(drv_data, chip);
547a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		bfin_spi_disable(drv_data);
548a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
549a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
550fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu	if (!drv_data->cs_change)
551bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		cs_deactive(drv_data, chip);
552fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu
553a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (msg->complete)
554a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		msg->complete(msg->context);
555a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
556a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
55788b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wustatic irqreturn_t dma_irq_handler(int irq, void *dev_id)
558a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
55915aafa2f9d8399b22e418c53a87dfc0c43f4030fJeff Garzik	struct driver_data *drv_data = dev_id;
560fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu	struct chip_data *chip = drv_data->cur_chip;
561bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	struct spi_message *msg = drv_data->cur_msg;
562d24bd1d0dc850e7aa68c27ec288eb699d41a5916Mike Frysinger	unsigned short dmastat = get_dma_curr_irqstat(drv_data->dma_channel);
56304b95d2f7453d64f89ca1d8c3e70bcc7cc38320fMike Frysinger	u16 spistat = read_STAT(drv_data);
564a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
565d24bd1d0dc850e7aa68c27ec288eb699d41a5916Mike Frysinger	dev_dbg(&drv_data->pdev->dev,
566d24bd1d0dc850e7aa68c27ec288eb699d41a5916Mike Frysinger		"in dma_irq_handler dmastat:0x%x spistat:0x%x\n",
567d24bd1d0dc850e7aa68c27ec288eb699d41a5916Mike Frysinger		dmastat, spistat);
568d24bd1d0dc850e7aa68c27ec288eb699d41a5916Mike Frysinger
569bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	clear_dma_irqstat(drv_data->dma_channel);
570a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
571d6fe89b0630080e2bd6ece20ff7b1b5c2647ed62Bryan Wu	/* Wait for DMA to complete */
572bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	while (get_dma_curr_irqstat(drv_data->dma_channel) & DMA_RUN)
573d8c05008b0e464c94967ed2f20d1d661fca6790eBryan Wu		cpu_relax();
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) {
582bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		while ((read_STAT(drv_data) & TXS) ||
583bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		       (read_STAT(drv_data) & TXS))
584d8c05008b0e464c94967ed2f20d1d661fca6790eBryan Wu			cpu_relax();
585a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
586a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
587bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	while (!(read_STAT(drv_data) & SPIF))
588d8c05008b0e464c94967ed2f20d1d661fca6790eBryan Wu		cpu_relax();
589a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
59004b95d2f7453d64f89ca1d8c3e70bcc7cc38320fMike Frysinger	if (spistat & RBSY) {
59104b95d2f7453d64f89ca1d8c3e70bcc7cc38320fMike Frysinger		msg->state = ERROR_STATE;
59204b95d2f7453d64f89ca1d8c3e70bcc7cc38320fMike Frysinger		dev_err(&drv_data->pdev->dev, "dma receive: fifo/buffer overflow\n");
59304b95d2f7453d64f89ca1d8c3e70bcc7cc38320fMike Frysinger	} else {
59404b95d2f7453d64f89ca1d8c3e70bcc7cc38320fMike Frysinger		msg->actual_length += drv_data->len_in_bytes;
595a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
59604b95d2f7453d64f89ca1d8c3e70bcc7cc38320fMike Frysinger		if (drv_data->cs_change)
59704b95d2f7453d64f89ca1d8c3e70bcc7cc38320fMike Frysinger			cs_deactive(drv_data, chip);
598fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu
59904b95d2f7453d64f89ca1d8c3e70bcc7cc38320fMike Frysinger		/* Move to next transfer */
60004b95d2f7453d64f89ca1d8c3e70bcc7cc38320fMike Frysinger		msg->state = next_transfer(drv_data);
60104b95d2f7453d64f89ca1d8c3e70bcc7cc38320fMike Frysinger	}
602a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
603a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Schedule transfer tasklet */
604a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	tasklet_schedule(&drv_data->pump_transfers);
605a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
606a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* free the irq handler before next transfer */
60788b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu	dev_dbg(&drv_data->pdev->dev,
60888b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu		"disable dma channel irq%d\n",
609bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		drv_data->dma_channel);
610bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	dma_disable_irq(drv_data->dma_channel);
611a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
612a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	return IRQ_HANDLED;
613a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
614a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
615a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic void pump_transfers(unsigned long data)
616a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
617a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct driver_data *drv_data = (struct driver_data *)data;
618a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct spi_message *message = NULL;
619a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct spi_transfer *transfer = NULL;
620a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct spi_transfer *previous = NULL;
621a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct chip_data *chip = NULL;
62288b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu	u8 width;
62388b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu	u16 cr, dma_width, dma_config;
624a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	u32 tranf_success = 1;
6258eeb12e5a2486ab958fa27ec97e71dabf234b73bVitja Makarov	u8 full_duplex = 0;
626a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
627a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Get current state information */
628a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	message = drv_data->cur_msg;
629a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	transfer = drv_data->cur_transfer;
630a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	chip = drv_data->cur_chip;
631092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu
632a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/*
633a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	 * if msg is error or done, report it back using complete() callback
634a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	 */
635a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
636a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	 /* Handle for abort */
637a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (message->state == ERROR_STATE) {
638d24bd1d0dc850e7aa68c27ec288eb699d41a5916Mike Frysinger		dev_dbg(&drv_data->pdev->dev, "transfer: we've hit an error\n");
639a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		message->status = -EIO;
640a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		giveback(drv_data);
641a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return;
642a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
643a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
644a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Handle end of message */
645a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (message->state == DONE_STATE) {
646d24bd1d0dc850e7aa68c27ec288eb699d41a5916Mike Frysinger		dev_dbg(&drv_data->pdev->dev, "transfer: all done!\n");
647a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		message->status = 0;
648a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		giveback(drv_data);
649a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return;
650a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
651a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
652a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Delay if requested at end of transfer */
653a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (message->state == RUNNING_STATE) {
654d24bd1d0dc850e7aa68c27ec288eb699d41a5916Mike Frysinger		dev_dbg(&drv_data->pdev->dev, "transfer: still running ...\n");
655a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		previous = list_entry(transfer->transfer_list.prev,
656a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan				      struct spi_transfer, transfer_list);
657a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		if (previous->delay_usecs)
658a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			udelay(previous->delay_usecs);
659a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
660a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
661a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Setup the transfer state based on the type of transfer */
662a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (flush(drv_data) == 0) {
663a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		dev_err(&drv_data->pdev->dev, "pump_transfers: flush failed\n");
664a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		message->status = -EIO;
665a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		giveback(drv_data);
666a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return;
667a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
668a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
669a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (transfer->tx_buf != NULL) {
670a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->tx = (void *)transfer->tx_buf;
671a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->tx_end = drv_data->tx + transfer->len;
67288b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu		dev_dbg(&drv_data->pdev->dev, "tx_buf is %p, tx_end is %p\n",
67388b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu			transfer->tx_buf, drv_data->tx_end);
674a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	} else {
675a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->tx = NULL;
676a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
677a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
678a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (transfer->rx_buf != NULL) {
6798eeb12e5a2486ab958fa27ec97e71dabf234b73bVitja Makarov		full_duplex = transfer->tx_buf != NULL;
680a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->rx = transfer->rx_buf;
681a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->rx_end = drv_data->rx + transfer->len;
68288b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu		dev_dbg(&drv_data->pdev->dev, "rx_buf is %p, rx_end is %p\n",
68388b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu			transfer->rx_buf, drv_data->rx_end);
684a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	} else {
685a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->rx = NULL;
686a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
687a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
688a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->rx_dma = transfer->rx_dma;
689a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->tx_dma = transfer->tx_dma;
690a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->len_in_bytes = transfer->len;
691fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu	drv_data->cs_change = transfer->cs_change;
692a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
693092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu	/* Bits per word setup */
694092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu	switch (transfer->bits_per_word) {
695092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu	case 8:
696092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu		drv_data->n_bytes = 1;
697092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu		width = CFG_SPI_WORDSIZE8;
698092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu		drv_data->read = chip->cs_change_per_word ?
699092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu			u8_cs_chg_reader : u8_reader;
700092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu		drv_data->write = chip->cs_change_per_word ?
701092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu			u8_cs_chg_writer : u8_writer;
702092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu		drv_data->duplex = chip->cs_change_per_word ?
703092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu			u8_cs_chg_duplex : u8_duplex;
704092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu		break;
705092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu
706092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu	case 16:
707092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu		drv_data->n_bytes = 2;
708092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu		width = CFG_SPI_WORDSIZE16;
709092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu		drv_data->read = chip->cs_change_per_word ?
710092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu			u16_cs_chg_reader : u16_reader;
711092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu		drv_data->write = chip->cs_change_per_word ?
712092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu			u16_cs_chg_writer : u16_writer;
713092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu		drv_data->duplex = chip->cs_change_per_word ?
714092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu			u16_cs_chg_duplex : u16_duplex;
715092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu		break;
716092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu
717092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu	default:
718092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu		/* No change, the same as default setting */
719092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu		drv_data->n_bytes = chip->n_bytes;
720092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu		width = chip->width;
721092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu		drv_data->write = drv_data->tx ? chip->write : null_writer;
722092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu		drv_data->read = drv_data->rx ? chip->read : null_reader;
723092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu		drv_data->duplex = chip->duplex ? chip->duplex : null_writer;
724092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu		break;
725092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu	}
726092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu	cr = (read_CTRL(drv_data) & (~BIT_CTL_TIMOD));
727092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu	cr |= (width << 8);
728092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu	write_CTRL(drv_data, cr);
729092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu
730a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (width == CFG_SPI_WORDSIZE16) {
731a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->len = (transfer->len) >> 1;
732a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	} else {
733a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->len = transfer->len;
734a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
7354fb98efacffd3dfbe8e3b9cb054dd71bab715065Mike Frysinger	dev_dbg(&drv_data->pdev->dev,
7364fb98efacffd3dfbe8e3b9cb054dd71bab715065Mike Frysinger		"transfer: drv_data->write is %p, chip->write is %p, null_wr is %p\n",
737131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu		drv_data->write, chip->write, null_writer);
738a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
739a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* speed and width has been set on per message */
740a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	message->state = RUNNING_STATE;
741a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	dma_config = 0;
742a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
743092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu	/* Speed setup (surely valid because already checked) */
744092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu	if (transfer->speed_hz)
745092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu		write_BAUD(drv_data, hz_to_spi_baud(transfer->speed_hz));
746092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu	else
747092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu		write_BAUD(drv_data, chip->baud);
748092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu
749bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	write_STAT(drv_data, BIT_STAT_CLR);
750bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	cr = (read_CTRL(drv_data) & (~BIT_CTL_TIMOD));
751bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	cs_active(drv_data, chip);
752a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
75388b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu	dev_dbg(&drv_data->pdev->dev,
75488b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu		"now pumping a transfer: width is %d, len is %d\n",
75588b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu		width, transfer->len);
756a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
757a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/*
7588cf5858c51f88208fe56b195251ab4f21265386cVitja Makarov	 * Try to map dma buffer and do a dma transfer.  If successful use,
7598cf5858c51f88208fe56b195251ab4f21265386cVitja Makarov	 * different way to r/w according to the enable_dma settings and if
7608cf5858c51f88208fe56b195251ab4f21265386cVitja Makarov	 * we are not doing a full duplex transfer (since the hardware does
7618cf5858c51f88208fe56b195251ab4f21265386cVitja Makarov	 * not support full duplex DMA transfers).
762a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	 */
7638eeb12e5a2486ab958fa27ec97e71dabf234b73bVitja Makarov	if (!full_duplex && drv_data->cur_chip->enable_dma
7648eeb12e5a2486ab958fa27ec97e71dabf234b73bVitja Makarov				&& drv_data->len > 6) {
765a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
7667aec35661733c651f616f9b3f69d758f6bfe2a7fMike Frysinger		unsigned long dma_start_addr;
7677aec35661733c651f616f9b3f69d758f6bfe2a7fMike Frysinger
768bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		disable_dma(drv_data->dma_channel);
769bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		clear_dma_irqstat(drv_data->dma_channel);
77007612e5f224613020c0ba17ce28e8eac052ef8ceSonic Zhang		bfin_spi_disable(drv_data);
771a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
772a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		/* config dma channel */
77388b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu		dev_dbg(&drv_data->pdev->dev, "doing dma transfer\n");
7747aec35661733c651f616f9b3f69d758f6bfe2a7fMike Frysinger		set_dma_x_count(drv_data->dma_channel, drv_data->len);
775a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		if (width == CFG_SPI_WORDSIZE16) {
776bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu			set_dma_x_modify(drv_data->dma_channel, 2);
777a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			dma_width = WDSIZE_16;
778a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		} else {
779bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu			set_dma_x_modify(drv_data->dma_channel, 1);
780a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			dma_width = WDSIZE_8;
781a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		}
782a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
7833f479a65b3f49ee4f058a965e6e33d97ee467b68Sonic Zhang		/* poll for SPI completion before start */
784bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
785d8c05008b0e464c94967ed2f20d1d661fca6790eBryan Wu			cpu_relax();
7863f479a65b3f49ee4f058a965e6e33d97ee467b68Sonic Zhang
787a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		/* dirty hack for autobuffer DMA mode */
788a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		if (drv_data->tx_dma == 0xFFFF) {
78988b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu			dev_dbg(&drv_data->pdev->dev,
79088b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu				"doing autobuffer DMA out.\n");
791a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
792a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			/* no irq in autobuffer mode */
793a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			dma_config =
794a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			    (DMAFLOW_AUTO | RESTART | dma_width | DI_EN);
795bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu			set_dma_config(drv_data->dma_channel, dma_config);
796bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu			set_dma_start_addr(drv_data->dma_channel,
797a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu					(unsigned long)drv_data->tx);
798bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu			enable_dma(drv_data->dma_channel);
799a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
80007612e5f224613020c0ba17ce28e8eac052ef8ceSonic Zhang			/* start SPI transfer */
80107612e5f224613020c0ba17ce28e8eac052ef8ceSonic Zhang			write_CTRL(drv_data,
80207612e5f224613020c0ba17ce28e8eac052ef8ceSonic Zhang				(cr | CFG_SPI_DMAWRITE | BIT_CTL_ENABLE));
80307612e5f224613020c0ba17ce28e8eac052ef8ceSonic Zhang
80407612e5f224613020c0ba17ce28e8eac052ef8ceSonic Zhang			/* just return here, there can only be one transfer
80507612e5f224613020c0ba17ce28e8eac052ef8ceSonic Zhang			 * in this mode
80607612e5f224613020c0ba17ce28e8eac052ef8ceSonic Zhang			 */
807a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			message->status = 0;
808a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			giveback(drv_data);
809a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			return;
810a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		}
811a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
812a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		/* In dma mode, rx or tx must be NULL in one transfer */
8137aec35661733c651f616f9b3f69d758f6bfe2a7fMike Frysinger		dma_config = (RESTART | dma_width | DI_EN);
814a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		if (drv_data->rx != NULL) {
815a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			/* set transfer mode, and enable SPI */
816d24bd1d0dc850e7aa68c27ec288eb699d41a5916Mike Frysinger			dev_dbg(&drv_data->pdev->dev, "doing DMA in to %p (size %zx)\n",
817d24bd1d0dc850e7aa68c27ec288eb699d41a5916Mike Frysinger				drv_data->rx, drv_data->len_in_bytes);
818a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
8198cf5858c51f88208fe56b195251ab4f21265386cVitja Makarov			/* invalidate caches, if needed */
8208cf5858c51f88208fe56b195251ab4f21265386cVitja Makarov			if (bfin_addr_dcachable((unsigned long) drv_data->rx))
8218cf5858c51f88208fe56b195251ab4f21265386cVitja Makarov				invalidate_dcache_range((unsigned long) drv_data->rx,
8228cf5858c51f88208fe56b195251ab4f21265386cVitja Makarov							(unsigned long) (drv_data->rx +
823ace32865a3767e4e385b883868c228a2a6db225aMike Frysinger							drv_data->len_in_bytes));
8248cf5858c51f88208fe56b195251ab4f21265386cVitja Makarov
825a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			/* clear tx reg soformer data is not shifted out */
826bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu			write_TDBR(drv_data, 0xFFFF);
827a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
8287aec35661733c651f616f9b3f69d758f6bfe2a7fMike Frysinger			dma_config |= WNR;
8297aec35661733c651f616f9b3f69d758f6bfe2a7fMike Frysinger			dma_start_addr = (unsigned long)drv_data->rx;
8307aec35661733c651f616f9b3f69d758f6bfe2a7fMike Frysinger			cr |= CFG_SPI_DMAREAD;
83107612e5f224613020c0ba17ce28e8eac052ef8ceSonic Zhang
832a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		} else if (drv_data->tx != NULL) {
83388b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu			dev_dbg(&drv_data->pdev->dev, "doing DMA out.\n");
834a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
8358cf5858c51f88208fe56b195251ab4f21265386cVitja Makarov			/* flush caches, if needed */
8368cf5858c51f88208fe56b195251ab4f21265386cVitja Makarov			if (bfin_addr_dcachable((unsigned long) drv_data->tx))
8378cf5858c51f88208fe56b195251ab4f21265386cVitja Makarov				flush_dcache_range((unsigned long) drv_data->tx,
8388cf5858c51f88208fe56b195251ab4f21265386cVitja Makarov						(unsigned long) (drv_data->tx +
839ace32865a3767e4e385b883868c228a2a6db225aMike Frysinger						drv_data->len_in_bytes));
8408cf5858c51f88208fe56b195251ab4f21265386cVitja Makarov
8417aec35661733c651f616f9b3f69d758f6bfe2a7fMike Frysinger			dma_start_addr = (unsigned long)drv_data->tx;
8427aec35661733c651f616f9b3f69d758f6bfe2a7fMike Frysinger			cr |= CFG_SPI_DMAWRITE;
8437aec35661733c651f616f9b3f69d758f6bfe2a7fMike Frysinger
8447aec35661733c651f616f9b3f69d758f6bfe2a7fMike Frysinger		} else
8457aec35661733c651f616f9b3f69d758f6bfe2a7fMike Frysinger			BUG();
8467aec35661733c651f616f9b3f69d758f6bfe2a7fMike Frysinger
8477aec35661733c651f616f9b3f69d758f6bfe2a7fMike Frysinger		/* start dma */
8487aec35661733c651f616f9b3f69d758f6bfe2a7fMike Frysinger		dma_enable_irq(drv_data->dma_channel);
8497aec35661733c651f616f9b3f69d758f6bfe2a7fMike Frysinger		set_dma_config(drv_data->dma_channel, dma_config);
8507aec35661733c651f616f9b3f69d758f6bfe2a7fMike Frysinger		set_dma_start_addr(drv_data->dma_channel, dma_start_addr);
8517aec35661733c651f616f9b3f69d758f6bfe2a7fMike Frysinger		enable_dma(drv_data->dma_channel);
8527aec35661733c651f616f9b3f69d758f6bfe2a7fMike Frysinger
8537aec35661733c651f616f9b3f69d758f6bfe2a7fMike Frysinger		/* start SPI transfer */
8547aec35661733c651f616f9b3f69d758f6bfe2a7fMike Frysinger		write_CTRL(drv_data, (cr | BIT_CTL_ENABLE));
85507612e5f224613020c0ba17ce28e8eac052ef8ceSonic Zhang
856a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	} else {
857a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		/* IO mode write then read */
85888b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu		dev_dbg(&drv_data->pdev->dev, "doing IO transfer\n");
859a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
8608eeb12e5a2486ab958fa27ec97e71dabf234b73bVitja Makarov		if (full_duplex) {
861a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			/* full duplex mode */
862a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			BUG_ON((drv_data->tx_end - drv_data->tx) !=
863a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			       (drv_data->rx_end - drv_data->rx));
86488b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu			dev_dbg(&drv_data->pdev->dev,
86588b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu				"IO duplex: cr is 0x%x\n", cr);
866a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
867cc487e732089360727e60f9fdbe3ff6cc4ca3155Sonic Zhang			/* set SPI transfer mode */
868bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu			write_CTRL(drv_data, (cr | CFG_SPI_WRITE));
869a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
870a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			drv_data->duplex(drv_data);
871a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
872a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			if (drv_data->tx != drv_data->tx_end)
873a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan				tranf_success = 0;
874a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		} else if (drv_data->tx != NULL) {
875a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			/* write only half duplex */
876131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu			dev_dbg(&drv_data->pdev->dev,
87788b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu				"IO write: cr is 0x%x\n", cr);
878a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
879cc487e732089360727e60f9fdbe3ff6cc4ca3155Sonic Zhang			/* set SPI transfer mode */
880bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu			write_CTRL(drv_data, (cr | CFG_SPI_WRITE));
881a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
882a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			drv_data->write(drv_data);
883a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
884a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			if (drv_data->tx != drv_data->tx_end)
885a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan				tranf_success = 0;
886a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		} else if (drv_data->rx != NULL) {
887a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			/* read only half duplex */
888131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu			dev_dbg(&drv_data->pdev->dev,
88988b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu				"IO read: cr is 0x%x\n", cr);
890a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
891cc487e732089360727e60f9fdbe3ff6cc4ca3155Sonic Zhang			/* set SPI transfer mode */
892bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu			write_CTRL(drv_data, (cr | CFG_SPI_READ));
893a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
894a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			drv_data->read(drv_data);
895a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			if (drv_data->rx != drv_data->rx_end)
896a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan				tranf_success = 0;
897a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		}
898a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
899a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		if (!tranf_success) {
900131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu			dev_dbg(&drv_data->pdev->dev,
90188b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu				"IO write error!\n");
902a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			message->state = ERROR_STATE;
903a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		} else {
904a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			/* Update total byte transfered */
905ace32865a3767e4e385b883868c228a2a6db225aMike Frysinger			message->actual_length += drv_data->len_in_bytes;
906a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
907a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			/* Move to next transfer of this msg */
908a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			message->state = next_transfer(drv_data);
909a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		}
910a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
911a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		/* Schedule next transfer tasklet */
912a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		tasklet_schedule(&drv_data->pump_transfers);
913a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
914a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
915a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
916a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
917a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan/* pop a msg from queue and kick off real transfer */
918a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic void pump_messages(struct work_struct *work)
919a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
920131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu	struct driver_data *drv_data;
921a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	unsigned long flags;
922a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
923131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu	drv_data = container_of(work, struct driver_data, pump_messages);
924131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu
925a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Lock queue and check for queue work */
926a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	spin_lock_irqsave(&drv_data->lock, flags);
927a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (list_empty(&drv_data->queue) || drv_data->run == QUEUE_STOPPED) {
928a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		/* pumper kicked off but no work to do */
929a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->busy = 0;
930a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		spin_unlock_irqrestore(&drv_data->lock, flags);
931a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return;
932a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
933a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
934a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Make sure we are not already running a message */
935a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (drv_data->cur_msg) {
936a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		spin_unlock_irqrestore(&drv_data->lock, flags);
937a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return;
938a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
939a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
940a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Extract head of queue */
941a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->cur_msg = list_entry(drv_data->queue.next,
942a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan				       struct spi_message, queue);
9435fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu
9445fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu	/* Setup the SSP using the per chip configuration */
9455fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu	drv_data->cur_chip = spi_get_ctldata(drv_data->cur_msg->spi);
9468d20d0a7c470cda37db6765866df6338f51ead0fBryan Wu	restore_state(drv_data);
9475fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu
948a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	list_del_init(&drv_data->cur_msg->queue);
949a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
950a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Initial message state */
951a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->cur_msg->state = START_STATE;
952a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->cur_transfer = list_entry(drv_data->cur_msg->transfers.next,
953a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan					    struct spi_transfer, transfer_list);
954a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
9555fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu	dev_dbg(&drv_data->pdev->dev, "got a message to pump, "
9565fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu		"state is set to: baud %d, flag 0x%x, ctl 0x%x\n",
9575fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu		drv_data->cur_chip->baud, drv_data->cur_chip->flag,
9585fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu		drv_data->cur_chip->ctl_reg);
959131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu
960131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu	dev_dbg(&drv_data->pdev->dev,
96188b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu		"the first transfer len is %d\n",
96288b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu		drv_data->cur_transfer->len);
963a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
964a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Mark as busy and launch transfers */
965a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	tasklet_schedule(&drv_data->pump_transfers);
966a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
967a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->busy = 1;
968a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	spin_unlock_irqrestore(&drv_data->lock, flags);
969a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
970a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
971a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan/*
972a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan * got a msg to transfer, queue it in drv_data->queue.
973a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan * And kick off message pumper
974a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan */
975a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic int transfer(struct spi_device *spi, struct spi_message *msg)
976a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
977a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct driver_data *drv_data = spi_master_get_devdata(spi->master);
978a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	unsigned long flags;
979a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
980a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	spin_lock_irqsave(&drv_data->lock, flags);
981a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
982a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (drv_data->run == QUEUE_STOPPED) {
983a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		spin_unlock_irqrestore(&drv_data->lock, flags);
984a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return -ESHUTDOWN;
985a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
986a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
987a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	msg->actual_length = 0;
988a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	msg->status = -EINPROGRESS;
989a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	msg->state = START_STATE;
990a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
99188b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu	dev_dbg(&spi->dev, "adding an msg in transfer() \n");
992a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	list_add_tail(&msg->queue, &drv_data->queue);
993a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
994a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (drv_data->run == QUEUE_RUNNING && !drv_data->busy)
995a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		queue_work(drv_data->workqueue, &drv_data->pump_messages);
996a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
997a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	spin_unlock_irqrestore(&drv_data->lock, flags);
998a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
999a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	return 0;
1000a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
1001a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
100212e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang#define MAX_SPI_SSEL	7
100312e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang
100412e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhangstatic u16 ssel[3][MAX_SPI_SSEL] = {
100512e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang	{P_SPI0_SSEL1, P_SPI0_SSEL2, P_SPI0_SSEL3,
100612e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang	P_SPI0_SSEL4, P_SPI0_SSEL5,
100712e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang	P_SPI0_SSEL6, P_SPI0_SSEL7},
100812e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang
100912e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang	{P_SPI1_SSEL1, P_SPI1_SSEL2, P_SPI1_SSEL3,
101012e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang	P_SPI1_SSEL4, P_SPI1_SSEL5,
101112e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang	P_SPI1_SSEL6, P_SPI1_SSEL7},
101212e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang
101312e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang	{P_SPI2_SSEL1, P_SPI2_SSEL2, P_SPI2_SSEL3,
101412e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang	P_SPI2_SSEL4, P_SPI2_SSEL5,
101512e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang	P_SPI2_SSEL6, P_SPI2_SSEL7},
101612e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang};
101712e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang
1018a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan/* first setup for new devices */
1019a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic int setup(struct spi_device *spi)
1020a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
1021a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct bfin5xx_spi_chip *chip_info = NULL;
1022a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct chip_data *chip;
1023a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct driver_data *drv_data = spi_master_get_devdata(spi->master);
1024a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	u8 spi_flg;
1025a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1026a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Abort device setup if requested features are not supported */
1027a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (spi->mode & ~(SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST)) {
1028a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		dev_err(&spi->dev, "requested mode not fully supported\n");
1029a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return -EINVAL;
1030a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
1031a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1032a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Zero (the default) here means 8 bits */
1033a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (!spi->bits_per_word)
1034a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		spi->bits_per_word = 8;
1035a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1036a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (spi->bits_per_word != 8 && spi->bits_per_word != 16)
1037a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return -EINVAL;
1038a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1039a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Only alloc (or use chip_info) on first setup */
1040a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	chip = spi_get_ctldata(spi);
1041a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (chip == NULL) {
1042a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);
1043a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		if (!chip)
1044a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			return -ENOMEM;
1045a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1046a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		chip->enable_dma = 0;
1047a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		chip_info = spi->controller_data;
1048a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
1049a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1050a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* chip_info isn't always needed */
1051a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (chip_info) {
10522ed355165ff4ec834a75770f2a15dc87f5e06088Mike Frysinger		/* Make sure people stop trying to set fields via ctl_reg
10532ed355165ff4ec834a75770f2a15dc87f5e06088Mike Frysinger		 * when they should actually be using common SPI framework.
10542ed355165ff4ec834a75770f2a15dc87f5e06088Mike Frysinger		 * Currently we let through: WOM EMISO PSSE GM SZ TIMOD.
10552ed355165ff4ec834a75770f2a15dc87f5e06088Mike Frysinger		 * Not sure if a user actually needs/uses any of these,
10562ed355165ff4ec834a75770f2a15dc87f5e06088Mike Frysinger		 * but let's assume (for now) they do.
10572ed355165ff4ec834a75770f2a15dc87f5e06088Mike Frysinger		 */
10582ed355165ff4ec834a75770f2a15dc87f5e06088Mike Frysinger		if (chip_info->ctl_reg & (SPE|MSTR|CPOL|CPHA|LSBF|SIZE)) {
10592ed355165ff4ec834a75770f2a15dc87f5e06088Mike Frysinger			dev_err(&spi->dev, "do not set bits in ctl_reg "
10602ed355165ff4ec834a75770f2a15dc87f5e06088Mike Frysinger				"that the SPI framework manages\n");
10612ed355165ff4ec834a75770f2a15dc87f5e06088Mike Frysinger			return -EINVAL;
10622ed355165ff4ec834a75770f2a15dc87f5e06088Mike Frysinger		}
10632ed355165ff4ec834a75770f2a15dc87f5e06088Mike Frysinger
1064a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		chip->enable_dma = chip_info->enable_dma != 0
1065a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		    && drv_data->master_info->enable_dma;
1066a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		chip->ctl_reg = chip_info->ctl_reg;
1067a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		chip->bits_per_word = chip_info->bits_per_word;
1068a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		chip->cs_change_per_word = chip_info->cs_change_per_word;
1069a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		chip->cs_chg_udelay = chip_info->cs_chg_udelay;
1070a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
1071a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1072a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* translate common spi framework into our register */
1073a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (spi->mode & SPI_CPOL)
1074a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		chip->ctl_reg |= CPOL;
1075a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (spi->mode & SPI_CPHA)
1076a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		chip->ctl_reg |= CPHA;
1077a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (spi->mode & SPI_LSB_FIRST)
1078a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		chip->ctl_reg |= LSBF;
1079a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* we dont support running in slave mode (yet?) */
1080a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	chip->ctl_reg |= MSTR;
1081a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1082a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/*
1083a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	 * if any one SPI chip is registered and wants DMA, request the
1084a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	 * DMA channel for it
1085a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	 */
1086bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	if (chip->enable_dma && !drv_data->dma_requested) {
1087a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		/* register dma irq handler */
108859bfcc664859029f60269ca2bf05b310d5a5760bMike Frysinger		if (request_dma(drv_data->dma_channel, "BFIN_SPI_DMA") < 0) {
108988b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu			dev_dbg(&spi->dev,
109088b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu				"Unable to request BlackFin SPI DMA channel\n");
1091a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			return -ENODEV;
1092a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		}
1093bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		if (set_dma_callback(drv_data->dma_channel,
109459bfcc664859029f60269ca2bf05b310d5a5760bMike Frysinger		    dma_irq_handler, drv_data) < 0) {
109588b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu			dev_dbg(&spi->dev, "Unable to set dma callback\n");
1096a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			return -EPERM;
1097a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		}
1098bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		dma_disable_irq(drv_data->dma_channel);
1099bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		drv_data->dma_requested = 1;
1100a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
1101a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1102a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/*
1103a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	 * Notice: for blackfin, the speed_hz is the value of register
1104a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	 * SPI_BAUD, not the real baudrate
1105a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	 */
1106a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	chip->baud = hz_to_spi_baud(spi->max_speed_hz);
1107a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	spi_flg = ~(1 << (spi->chip_select));
1108a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	chip->flag = ((u16) spi_flg << 8) | (1 << (spi->chip_select));
1109a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	chip->chip_select_num = spi->chip_select;
1110a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1111a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	switch (chip->bits_per_word) {
1112a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	case 8:
1113a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		chip->n_bytes = 1;
1114a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		chip->width = CFG_SPI_WORDSIZE8;
1115a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		chip->read = chip->cs_change_per_word ?
1116a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			u8_cs_chg_reader : u8_reader;
1117a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		chip->write = chip->cs_change_per_word ?
1118a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			u8_cs_chg_writer : u8_writer;
1119a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		chip->duplex = chip->cs_change_per_word ?
1120a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			u8_cs_chg_duplex : u8_duplex;
1121a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		break;
1122a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1123a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	case 16:
1124a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		chip->n_bytes = 2;
1125a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		chip->width = CFG_SPI_WORDSIZE16;
1126a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		chip->read = chip->cs_change_per_word ?
1127a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			u16_cs_chg_reader : u16_reader;
1128a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		chip->write = chip->cs_change_per_word ?
1129a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			u16_cs_chg_writer : u16_writer;
1130a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		chip->duplex = chip->cs_change_per_word ?
1131a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			u16_cs_chg_duplex : u16_duplex;
1132a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		break;
1133a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1134a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	default:
1135a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		dev_err(&spi->dev, "%d bits_per_word is not supported\n",
1136a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan				chip->bits_per_word);
1137a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		kfree(chip);
1138a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return -ENODEV;
1139a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
1140a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1141898eb71cb17644964c5895fb190e79e3d0c49679Joe Perches	dev_dbg(&spi->dev, "setup spi chip %s, width is %d, dma is %d\n",
1142a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			spi->modalias, chip->width, chip->enable_dma);
114388b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu	dev_dbg(&spi->dev, "ctl_reg is 0x%x, flag_reg is 0x%x\n",
1144a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			chip->ctl_reg, chip->flag);
1145a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1146a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	spi_set_ctldata(spi, chip);
1147a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
114812e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang	dev_dbg(&spi->dev, "chip select number is %d\n", chip->chip_select_num);
114912e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang	if ((chip->chip_select_num > 0)
115012e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang		&& (chip->chip_select_num <= spi->master->num_chipselect))
115112e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang		peripheral_request(ssel[spi->master->bus_num]
1152aab0d83ee771b19082c3ee24576cf5508d319294Bryan Wu			[chip->chip_select_num-1], spi->modalias);
115312e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang
115407612e5f224613020c0ba17ce28e8eac052ef8ceSonic Zhang	cs_deactive(drv_data, chip);
115507612e5f224613020c0ba17ce28e8eac052ef8ceSonic Zhang
1156a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	return 0;
1157a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
1158a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1159a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan/*
1160a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan * callback for spi framework.
1161a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan * clean driver specific data
1162a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan */
116388b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wustatic void cleanup(struct spi_device *spi)
1164a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
116527bb9e79bcfedc1888d23c3c212c189fa8534fe7Mike Frysinger	struct chip_data *chip = spi_get_ctldata(spi);
1166a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
116712e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang	if ((chip->chip_select_num > 0)
116812e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang		&& (chip->chip_select_num <= spi->master->num_chipselect))
116912e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang		peripheral_free(ssel[spi->master->bus_num]
117012e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang					[chip->chip_select_num-1]);
117112e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang
1172a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	kfree(chip);
1173a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
1174a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1175a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic inline int init_queue(struct driver_data *drv_data)
1176a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
1177a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	INIT_LIST_HEAD(&drv_data->queue);
1178a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	spin_lock_init(&drv_data->lock);
1179a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1180a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->run = QUEUE_STOPPED;
1181a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->busy = 0;
1182a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1183a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* init transfer tasklet */
1184a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	tasklet_init(&drv_data->pump_transfers,
1185a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		     pump_transfers, (unsigned long)drv_data);
1186a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1187a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* init messages workqueue */
1188a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	INIT_WORK(&drv_data->pump_messages, pump_messages);
11896c7377ab6814c247d7600955a4ead2e3db490697Kay Sievers	drv_data->workqueue = create_singlethread_workqueue(
11906c7377ab6814c247d7600955a4ead2e3db490697Kay Sievers				dev_name(drv_data->master->dev.parent));
1191a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (drv_data->workqueue == NULL)
1192a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return -EBUSY;
1193a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1194a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	return 0;
1195a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
1196a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1197a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic inline int start_queue(struct driver_data *drv_data)
1198a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
1199a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	unsigned long flags;
1200a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1201a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	spin_lock_irqsave(&drv_data->lock, flags);
1202a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1203a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (drv_data->run == QUEUE_RUNNING || drv_data->busy) {
1204a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		spin_unlock_irqrestore(&drv_data->lock, flags);
1205a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return -EBUSY;
1206a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
1207a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1208a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->run = QUEUE_RUNNING;
1209a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->cur_msg = NULL;
1210a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->cur_transfer = NULL;
1211a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->cur_chip = NULL;
1212a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	spin_unlock_irqrestore(&drv_data->lock, flags);
1213a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1214a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	queue_work(drv_data->workqueue, &drv_data->pump_messages);
1215a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1216a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	return 0;
1217a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
1218a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1219a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic inline int stop_queue(struct driver_data *drv_data)
1220a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
1221a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	unsigned long flags;
1222a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	unsigned limit = 500;
1223a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	int status = 0;
1224a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1225a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	spin_lock_irqsave(&drv_data->lock, flags);
1226a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1227a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/*
1228a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	 * This is a bit lame, but is optimized for the common execution path.
1229a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	 * A wait_queue on the drv_data->busy could be used, but then the common
1230a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	 * execution path (pump_messages) would be required to call wake_up or
1231a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	 * friends on every SPI message. Do this instead
1232a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	 */
1233a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->run = QUEUE_STOPPED;
1234a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	while (!list_empty(&drv_data->queue) && drv_data->busy && limit--) {
1235a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		spin_unlock_irqrestore(&drv_data->lock, flags);
1236a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		msleep(10);
1237a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		spin_lock_irqsave(&drv_data->lock, flags);
1238a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
1239a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1240a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (!list_empty(&drv_data->queue) || drv_data->busy)
1241a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		status = -EBUSY;
1242a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1243a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	spin_unlock_irqrestore(&drv_data->lock, flags);
1244a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1245a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	return status;
1246a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
1247a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1248a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic inline int destroy_queue(struct driver_data *drv_data)
1249a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
1250a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	int status;
1251a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1252a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	status = stop_queue(drv_data);
1253a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (status != 0)
1254a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return status;
1255a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1256a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	destroy_workqueue(drv_data->workqueue);
1257a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1258a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	return 0;
1259a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
1260a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1261a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic int __init bfin5xx_spi_probe(struct platform_device *pdev)
1262a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
1263a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct device *dev = &pdev->dev;
1264a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct bfin5xx_spi_master *platform_info;
1265a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct spi_master *master;
1266a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct driver_data *drv_data = 0;
1267a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu	struct resource *res;
1268a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	int status = 0;
1269a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1270a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	platform_info = dev->platform_data;
1271a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1272a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Allocate master with space for drv_data */
1273a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	master = spi_alloc_master(dev, sizeof(struct driver_data) + 16);
1274a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (!master) {
1275a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		dev_err(&pdev->dev, "can not alloc spi_master\n");
1276a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return -ENOMEM;
1277a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
1278131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu
1279a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data = spi_master_get_devdata(master);
1280a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->master = master;
1281a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->master_info = platform_info;
1282a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->pdev = pdev;
1283003d922618150eaab53936f57ba8a61f2b601486Bryan Wu	drv_data->pin_req = platform_info->pin_req;
1284a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1285a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	master->bus_num = pdev->id;
1286a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	master->num_chipselect = platform_info->num_chipselect;
1287a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	master->cleanup = cleanup;
1288a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	master->setup = setup;
1289a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	master->transfer = transfer;
1290a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1291a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu	/* Find and map our resources */
1292a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1293a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu	if (res == NULL) {
1294a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu		dev_err(dev, "Cannot get IORESOURCE_MEM\n");
1295a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu		status = -ENOENT;
1296a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu		goto out_error_get_res;
1297a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu	}
1298a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu
1299f452126c2e4b8bbfd8e41ebdf1e734e3bf18f8e9Bryan Wu	drv_data->regs_base = ioremap(res->start, (res->end - res->start + 1));
1300f452126c2e4b8bbfd8e41ebdf1e734e3bf18f8e9Bryan Wu	if (drv_data->regs_base == NULL) {
1301a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu		dev_err(dev, "Cannot map IO\n");
1302a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu		status = -ENXIO;
1303a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu		goto out_error_ioremap;
1304a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu	}
1305a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu
1306bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	drv_data->dma_channel = platform_get_irq(pdev, 0);
1307bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	if (drv_data->dma_channel < 0) {
1308a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu		dev_err(dev, "No DMA channel specified\n");
1309a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu		status = -ENOENT;
1310a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu		goto out_error_no_dma_ch;
1311a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu	}
1312a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu
1313a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Initial and start queue */
1314a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	status = init_queue(drv_data);
1315a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (status != 0) {
1316a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu		dev_err(dev, "problem initializing queue\n");
1317a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		goto out_error_queue_alloc;
1318a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
1319a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu
1320a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	status = start_queue(drv_data);
1321a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (status != 0) {
1322a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu		dev_err(dev, "problem starting queue\n");
1323a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		goto out_error_queue_alloc;
1324a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
1325a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1326f9e522caece074b9a985436d611127e8e96ad446Vitja Makarov	status = peripheral_request_list(drv_data->pin_req, DRV_NAME);
1327f9e522caece074b9a985436d611127e8e96ad446Vitja Makarov	if (status != 0) {
1328f9e522caece074b9a985436d611127e8e96ad446Vitja Makarov		dev_err(&pdev->dev, ": Requesting Peripherals failed\n");
1329f9e522caece074b9a985436d611127e8e96ad446Vitja Makarov		goto out_error_queue_alloc;
1330f9e522caece074b9a985436d611127e8e96ad446Vitja Makarov	}
1331f9e522caece074b9a985436d611127e8e96ad446Vitja Makarov
1332a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Register with the SPI framework */
1333a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	platform_set_drvdata(pdev, drv_data);
1334a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	status = spi_register_master(master);
1335a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (status != 0) {
1336a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu		dev_err(dev, "problem registering spi master\n");
1337a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		goto out_error_queue_alloc;
1338a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
1339a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu
1340f452126c2e4b8bbfd8e41ebdf1e734e3bf18f8e9Bryan Wu	dev_info(dev, "%s, Version %s, regs_base@%p, dma channel@%d\n",
1341bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		DRV_DESC, DRV_VERSION, drv_data->regs_base,
1342bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		drv_data->dma_channel);
1343a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	return status;
1344a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1345cc2f81a695640dd1c0cf12b35ee303460fa6d0bcMichael Hennerichout_error_queue_alloc:
1346a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	destroy_queue(drv_data);
1347a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wuout_error_no_dma_ch:
1348bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	iounmap((void *) drv_data->regs_base);
1349a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wuout_error_ioremap:
1350a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wuout_error_get_res:
1351a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	spi_master_put(master);
1352cc2f81a695640dd1c0cf12b35ee303460fa6d0bcMichael Hennerich
1353a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	return status;
1354a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
1355a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1356a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan/* stop hardware and remove the driver */
1357a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic int __devexit bfin5xx_spi_remove(struct platform_device *pdev)
1358a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
1359a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct driver_data *drv_data = platform_get_drvdata(pdev);
1360a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	int status = 0;
1361a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1362a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (!drv_data)
1363a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return 0;
1364a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1365a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Remove the queue */
1366a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	status = destroy_queue(drv_data);
1367a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (status != 0)
1368a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return status;
1369a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1370a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Disable the SSP at the peripheral and SOC level */
1371a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	bfin_spi_disable(drv_data);
1372a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1373a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Release DMA */
1374a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (drv_data->master_info->enable_dma) {
1375bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		if (dma_channel_active(drv_data->dma_channel))
1376bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu			free_dma(drv_data->dma_channel);
1377a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
1378a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1379a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Disconnect from the SPI framework */
1380a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	spi_unregister_master(drv_data->master);
1381a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1382003d922618150eaab53936f57ba8a61f2b601486Bryan Wu	peripheral_free_list(drv_data->pin_req);
1383cc2f81a695640dd1c0cf12b35ee303460fa6d0bcMichael Hennerich
1384a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Prevent double remove */
1385a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	platform_set_drvdata(pdev, NULL);
1386a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1387a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	return 0;
1388a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
1389a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1390a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#ifdef CONFIG_PM
1391a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic int bfin5xx_spi_suspend(struct platform_device *pdev, pm_message_t state)
1392a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
1393a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct driver_data *drv_data = platform_get_drvdata(pdev);
1394a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	int status = 0;
1395a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1396a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	status = stop_queue(drv_data);
1397a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (status != 0)
1398a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return status;
1399a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1400a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* stop hardware */
1401a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	bfin_spi_disable(drv_data);
1402a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1403a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	return 0;
1404a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
1405a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1406a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic int bfin5xx_spi_resume(struct platform_device *pdev)
1407a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
1408a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct driver_data *drv_data = platform_get_drvdata(pdev);
1409a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	int status = 0;
1410a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1411a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Enable the SPI interface */
1412a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	bfin_spi_enable(drv_data);
1413a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1414a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Start the queue running */
1415a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	status = start_queue(drv_data);
1416a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (status != 0) {
1417a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		dev_err(&pdev->dev, "problem starting queue (%d)\n", status);
1418a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return status;
1419a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
1420a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1421a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	return 0;
1422a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
1423a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#else
1424a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#define bfin5xx_spi_suspend NULL
1425a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#define bfin5xx_spi_resume NULL
1426a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#endif				/* CONFIG_PM */
1427a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
14287e38c3c4453bdb5ffdf8bf0ff0d9a760540f0893Kay SieversMODULE_ALIAS("platform:bfin-spi");
1429a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic struct platform_driver bfin5xx_spi_driver = {
1430fc3ba9525b50ea0d1670357ece21ebedcee507aeDavid Brownell	.driver	= {
1431a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu		.name	= DRV_NAME,
143288b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu		.owner	= THIS_MODULE,
143388b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu	},
143488b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu	.suspend	= bfin5xx_spi_suspend,
143588b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu	.resume		= bfin5xx_spi_resume,
143688b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu	.remove		= __devexit_p(bfin5xx_spi_remove),
1437a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan};
1438a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1439a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic int __init bfin5xx_spi_init(void)
1440a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
144188b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu	return platform_driver_probe(&bfin5xx_spi_driver, bfin5xx_spi_probe);
1442a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
1443a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanmodule_init(bfin5xx_spi_init);
1444a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1445a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic void __exit bfin5xx_spi_exit(void)
1446a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
1447a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	platform_driver_unregister(&bfin5xx_spi_driver);
1448a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
1449a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanmodule_exit(bfin5xx_spi_exit);
1450