1a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan/*
226fdc1f0df22dd14fd4161ccb2fad94a3a938c48Mike Frysinger * Blackfin On-Chip SPI Driver
3a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan *
49c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysinger * Copyright 2004-2010 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>
155a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
16131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu#include <linux/io.h>
17a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#include <linux/ioport.h>
18131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu#include <linux/irq.h>
19a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#include <linux/errno.h>
20a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#include <linux/interrupt.h>
21a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#include <linux/platform_device.h>
22a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#include <linux/dma-mapping.h>
23a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#include <linux/spi/spi.h>
24a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#include <linux/workqueue.h>
25a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
26a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#include <asm/dma.h>
27131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu#include <asm/portmux.h>
28a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#include <asm/bfin5xx_spi.h>
298cf5858c51f88208fe56b195251ab4f21265386cVitja Makarov#include <asm/cacheflush.h>
308cf5858c51f88208fe56b195251ab4f21265386cVitja Makarov
31a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu#define DRV_NAME	"bfin-spi"
32a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu#define DRV_AUTHOR	"Bryan Wu, Luke Yang"
33138f97cd06deddd53ad496ac1656917a7b486d24Mike Frysinger#define DRV_DESC	"Blackfin on-chip SPI Controller Driver"
34a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu#define DRV_VERSION	"1.0"
35a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu
36a32c691d7cf5c37af753255ef4843b18a31935b9Bryan WuMODULE_AUTHOR(DRV_AUTHOR);
37a32c691d7cf5c37af753255ef4843b18a31935b9Bryan WuMODULE_DESCRIPTION(DRV_DESC);
38a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, BryanMODULE_LICENSE("GPL");
39a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
40bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu#define START_STATE	((void *)0)
41bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu#define RUNNING_STATE	((void *)1)
42bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu#define DONE_STATE	((void *)2)
43bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu#define ERROR_STATE	((void *)-1)
44a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
459c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysingerstruct bfin_spi_master_data;
469c4542c7a3082bf74f00145355ef407ac82c0b3fMike Frysinger
479c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysingerstruct bfin_spi_transfer_ops {
489c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysinger	void (*write) (struct bfin_spi_master_data *);
499c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysinger	void (*read) (struct bfin_spi_master_data *);
509c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysinger	void (*duplex) (struct bfin_spi_master_data *);
519c4542c7a3082bf74f00145355ef407ac82c0b3fMike Frysinger};
529c4542c7a3082bf74f00145355ef407ac82c0b3fMike Frysinger
539c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysingerstruct bfin_spi_master_data {
54a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Driver model hookup */
55a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct platform_device *pdev;
56a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
57a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* SPI framework hookup */
58a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct spi_master *master;
59a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
60bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	/* Regs base of SPI controller */
6147885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger	struct bfin_spi_regs __iomem *regs;
62bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu
63003d922618150eaab53936f57ba8a61f2b601486Bryan Wu	/* Pin request list */
64003d922618150eaab53936f57ba8a61f2b601486Bryan Wu	u16 *pin_req;
65003d922618150eaab53936f57ba8a61f2b601486Bryan Wu
66a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* BFIN hookup */
67a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct bfin5xx_spi_master *master_info;
68a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
69a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Driver message queue */
70a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct workqueue_struct *workqueue;
71a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct work_struct pump_messages;
72a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	spinlock_t lock;
73a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct list_head queue;
74a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	int busy;
75f4f50c3ff7815d83dcbb19341f35db2f408ac4f8Mike Frysinger	bool running;
76a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
77a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Message Transfer pump */
78a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct tasklet_struct pump_transfers;
79a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
80a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Current message transfer state info */
81a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct spi_message *cur_msg;
82a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct spi_transfer *cur_transfer;
839c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysinger	struct bfin_spi_slave_data *cur_chip;
84a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	size_t len_in_bytes;
85a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	size_t len;
86a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	void *tx;
87a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	void *tx_end;
88a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	void *rx;
89a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	void *rx_end;
90bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu
91bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	/* DMA stuffs */
92bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	int dma_channel;
93a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	int dma_mapped;
94bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	int dma_requested;
95a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	dma_addr_t rx_dma;
96a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	dma_addr_t tx_dma;
97bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu
98f6a6d96685be6e784849d067b44acb831f595417Yi Li	int irq_requested;
99f6a6d96685be6e784849d067b44acb831f595417Yi Li	int spi_irq;
100f6a6d96685be6e784849d067b44acb831f595417Yi Li
101a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	size_t rx_map_len;
102a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	size_t tx_map_len;
103a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	u8 n_bytes;
104b052fd0a44354c655eb98fd715ef52857631dfefBarry Song	u16 ctrl_reg;
105b052fd0a44354c655eb98fd715ef52857631dfefBarry Song	u16 flag_reg;
106b052fd0a44354c655eb98fd715ef52857631dfefBarry Song
107fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu	int cs_change;
1089c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysinger	const struct bfin_spi_transfer_ops *ops;
109a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan};
110a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1119c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysingerstruct bfin_spi_slave_data {
112a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	u16 ctl_reg;
113a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	u16 baud;
114a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	u16 flag;
115a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
116a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	u8 chip_select_num;
117a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	u8 enable_dma;
11862310e51ac10c5e50998240e49a84d2e28377a48Bryan Wu	u16 cs_chg_udelay;	/* Some devices require > 255usec delay */
11942c78b2bf51bafb4cfa98dfecc28dd9b8bcd04b0Michael Hennerich	u32 cs_gpio;
12093b61bddc13d9acf1fe341b39d826e80f3182d1eWolfgang Muees	u16 idle_tx_val;
121f6a6d96685be6e784849d067b44acb831f595417Yi Li	u8 pio_interrupt;	/* use spi data irq */
1229c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysinger	const struct bfin_spi_transfer_ops *ops;
123a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan};
124a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1259c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysingerstatic void bfin_spi_enable(struct bfin_spi_master_data *drv_data)
126a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
12747885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger	bfin_write_or(&drv_data->regs->ctl, BIT_CTL_ENABLE);
128a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
129a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1309c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysingerstatic void bfin_spi_disable(struct bfin_spi_master_data *drv_data)
131a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
13247885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger	bfin_write_and(&drv_data->regs->ctl, ~BIT_CTL_ENABLE);
133a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
134a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
135a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan/* Caculate the SPI_BAUD register value based on input HZ */
136a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryanstatic u16 hz_to_spi_baud(u32 speed_hz)
137a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
138a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	u_long sclk = get_sclk();
139a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	u16 spi_baud = (sclk / (2 * speed_hz));
140a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
141a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if ((sclk % (2 * speed_hz)) > 0)
142a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		spi_baud++;
143a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1447513e006c64fbe2f43aef2139c8c1f2b1a9cb6b9Michael Hennerich	if (spi_baud < MIN_SPI_BAUD_VAL)
1457513e006c64fbe2f43aef2139c8c1f2b1a9cb6b9Michael Hennerich		spi_baud = MIN_SPI_BAUD_VAL;
1467513e006c64fbe2f43aef2139c8c1f2b1a9cb6b9Michael Hennerich
147a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	return spi_baud;
148a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
149a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1509c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysingerstatic int bfin_spi_flush(struct bfin_spi_master_data *drv_data)
151a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
152a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	unsigned long limit = loops_per_jiffy << 1;
153a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
154a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* wait for stop and clear stat */
15547885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger	while (!(bfin_read(&drv_data->regs->stat) & BIT_STAT_SPIF) && --limit)
156d8c05008b0e464c94967ed2f20d1d661fca6790eBryan Wu		cpu_relax();
157a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
15847885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger	bfin_write(&drv_data->regs->stat, BIT_STAT_CLR);
159a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
160a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	return limit;
161a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
162a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
163fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu/* Chip select operation functions for cs_change flag */
1649c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysingerstatic void bfin_spi_cs_active(struct bfin_spi_master_data *drv_data, struct bfin_spi_slave_data *chip)
165fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu{
16647885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger	if (likely(chip->chip_select_num < MAX_CTRL_CS))
16747885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger		bfin_write_and(&drv_data->regs->flg, ~chip->flag);
16847885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger	else
16942c78b2bf51bafb4cfa98dfecc28dd9b8bcd04b0Michael Hennerich		gpio_set_value(chip->cs_gpio, 0);
170fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu}
171fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu
1729c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysingerstatic void bfin_spi_cs_deactive(struct bfin_spi_master_data *drv_data,
1739c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysinger                                 struct bfin_spi_slave_data *chip)
174fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu{
17547885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger	if (likely(chip->chip_select_num < MAX_CTRL_CS))
17647885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger		bfin_write_or(&drv_data->regs->flg, chip->flag);
17747885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger	else
17842c78b2bf51bafb4cfa98dfecc28dd9b8bcd04b0Michael Hennerich		gpio_set_value(chip->cs_gpio, 1);
17962310e51ac10c5e50998240e49a84d2e28377a48Bryan Wu
18062310e51ac10c5e50998240e49a84d2e28377a48Bryan Wu	/* Move delay here for consistency */
18162310e51ac10c5e50998240e49a84d2e28377a48Bryan Wu	if (chip->cs_chg_udelay)
18262310e51ac10c5e50998240e49a84d2e28377a48Bryan Wu		udelay(chip->cs_chg_udelay);
183fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu}
184fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu
1858221610e9990e7ee542a4e508d278302af8a9e75Barry Song/* enable or disable the pin muxed by GPIO and SPI CS to work as SPI CS */
1869c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysingerstatic inline void bfin_spi_cs_enable(struct bfin_spi_master_data *drv_data,
1879c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysinger                                      struct bfin_spi_slave_data *chip)
1888221610e9990e7ee542a4e508d278302af8a9e75Barry Song{
18947885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger	if (chip->chip_select_num < MAX_CTRL_CS)
19047885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger		bfin_write_or(&drv_data->regs->flg, chip->flag >> 8);
1918221610e9990e7ee542a4e508d278302af8a9e75Barry Song}
1928221610e9990e7ee542a4e508d278302af8a9e75Barry Song
1939c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysingerstatic inline void bfin_spi_cs_disable(struct bfin_spi_master_data *drv_data,
1949c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysinger                                       struct bfin_spi_slave_data *chip)
1958221610e9990e7ee542a4e508d278302af8a9e75Barry Song{
19647885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger	if (chip->chip_select_num < MAX_CTRL_CS)
19747885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger		bfin_write_and(&drv_data->regs->flg, ~(chip->flag >> 8));
1988221610e9990e7ee542a4e508d278302af8a9e75Barry Song}
1998221610e9990e7ee542a4e508d278302af8a9e75Barry Song
200a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan/* stop controller and re-config current chip*/
2019c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysingerstatic void bfin_spi_restore_state(struct bfin_spi_master_data *drv_data)
202a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
2039c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysinger	struct bfin_spi_slave_data *chip = drv_data->cur_chip;
20412e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang
205a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Clear status and disable clock */
20647885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger	bfin_write(&drv_data->regs->stat, BIT_STAT_CLR);
207a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	bfin_spi_disable(drv_data);
20888b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu	dev_dbg(&drv_data->pdev->dev, "restoring spi ctl state\n");
209a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
2109677b0de10433d31e05864dfb4bf33d0c27f752aBarry Song	SSYNC();
2119677b0de10433d31e05864dfb4bf33d0c27f752aBarry Song
2125fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu	/* Load the registers */
21347885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger	bfin_write(&drv_data->regs->ctl, chip->ctl_reg);
21447885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger	bfin_write(&drv_data->regs->baud, chip->baud);
215cc487e732089360727e60f9fdbe3ff6cc4ca3155Sonic Zhang
216cc487e732089360727e60f9fdbe3ff6cc4ca3155Sonic Zhang	bfin_spi_enable(drv_data);
217138f97cd06deddd53ad496ac1656917a7b486d24Mike Frysinger	bfin_spi_cs_active(drv_data, chip);
218a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
219a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
22093b61bddc13d9acf1fe341b39d826e80f3182d1eWolfgang Muees/* used to kick off transfer in rx mode and read unwanted RX data */
2219c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysingerstatic inline void bfin_spi_dummy_read(struct bfin_spi_master_data *drv_data)
222a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
22347885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger	(void) bfin_read(&drv_data->regs->rdbr);
224a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
225a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
2269c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysingerstatic void bfin_spi_u8_writer(struct bfin_spi_master_data *drv_data)
227a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
22893b61bddc13d9acf1fe341b39d826e80f3182d1eWolfgang Muees	/* clear RXS (we check for RXS inside the loop) */
22993b61bddc13d9acf1fe341b39d826e80f3182d1eWolfgang Muees	bfin_spi_dummy_read(drv_data);
230cc487e732089360727e60f9fdbe3ff6cc4ca3155Sonic Zhang
231a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	while (drv_data->tx < drv_data->tx_end) {
23247885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger		bfin_write(&drv_data->regs->tdbr, (*(u8 *) (drv_data->tx++)));
23393b61bddc13d9acf1fe341b39d826e80f3182d1eWolfgang Muees		/* wait until transfer finished.
23493b61bddc13d9acf1fe341b39d826e80f3182d1eWolfgang Muees		   checking SPIF or TXS may not guarantee transfer completion */
23547885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger		while (!(bfin_read(&drv_data->regs->stat) & BIT_STAT_RXS))
236d8c05008b0e464c94967ed2f20d1d661fca6790eBryan Wu			cpu_relax();
23793b61bddc13d9acf1fe341b39d826e80f3182d1eWolfgang Muees		/* discard RX data and clear RXS */
23893b61bddc13d9acf1fe341b39d826e80f3182d1eWolfgang Muees		bfin_spi_dummy_read(drv_data);
239a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
240a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
241a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
2429c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysingerstatic void bfin_spi_u8_reader(struct bfin_spi_master_data *drv_data)
243a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
24493b61bddc13d9acf1fe341b39d826e80f3182d1eWolfgang Muees	u16 tx_val = drv_data->cur_chip->idle_tx_val;
245a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
24693b61bddc13d9acf1fe341b39d826e80f3182d1eWolfgang Muees	/* discard old RX data and clear RXS */
247138f97cd06deddd53ad496ac1656917a7b486d24Mike Frysinger	bfin_spi_dummy_read(drv_data);
248cc487e732089360727e60f9fdbe3ff6cc4ca3155Sonic Zhang
24993b61bddc13d9acf1fe341b39d826e80f3182d1eWolfgang Muees	while (drv_data->rx < drv_data->rx_end) {
25047885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger		bfin_write(&drv_data->regs->tdbr, tx_val);
25147885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger		while (!(bfin_read(&drv_data->regs->stat) & BIT_STAT_RXS))
252d8c05008b0e464c94967ed2f20d1d661fca6790eBryan Wu			cpu_relax();
25347885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger		*(u8 *) (drv_data->rx++) = bfin_read(&drv_data->regs->rdbr);
254a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
255a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
256a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
2579c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysingerstatic void bfin_spi_u8_duplex(struct bfin_spi_master_data *drv_data)
258a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
25993b61bddc13d9acf1fe341b39d826e80f3182d1eWolfgang Muees	/* discard old RX data and clear RXS */
26093b61bddc13d9acf1fe341b39d826e80f3182d1eWolfgang Muees	bfin_spi_dummy_read(drv_data);
26193b61bddc13d9acf1fe341b39d826e80f3182d1eWolfgang Muees
262a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	while (drv_data->rx < drv_data->rx_end) {
26347885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger		bfin_write(&drv_data->regs->tdbr, (*(u8 *) (drv_data->tx++)));
26447885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger		while (!(bfin_read(&drv_data->regs->stat) & BIT_STAT_RXS))
265d8c05008b0e464c94967ed2f20d1d661fca6790eBryan Wu			cpu_relax();
26647885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger		*(u8 *) (drv_data->rx++) = bfin_read(&drv_data->regs->rdbr);
267a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
268a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
269a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
2709c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysingerstatic const struct bfin_spi_transfer_ops bfin_bfin_spi_transfer_ops_u8 = {
2719c4542c7a3082bf74f00145355ef407ac82c0b3fMike Frysinger	.write  = bfin_spi_u8_writer,
2729c4542c7a3082bf74f00145355ef407ac82c0b3fMike Frysinger	.read   = bfin_spi_u8_reader,
2739c4542c7a3082bf74f00145355ef407ac82c0b3fMike Frysinger	.duplex = bfin_spi_u8_duplex,
2749c4542c7a3082bf74f00145355ef407ac82c0b3fMike Frysinger};
2759c4542c7a3082bf74f00145355ef407ac82c0b3fMike Frysinger
2769c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysingerstatic void bfin_spi_u16_writer(struct bfin_spi_master_data *drv_data)
277a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
27893b61bddc13d9acf1fe341b39d826e80f3182d1eWolfgang Muees	/* clear RXS (we check for RXS inside the loop) */
27993b61bddc13d9acf1fe341b39d826e80f3182d1eWolfgang Muees	bfin_spi_dummy_read(drv_data);
28088b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu
281a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	while (drv_data->tx < drv_data->tx_end) {
28247885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger		bfin_write(&drv_data->regs->tdbr, (*(u16 *) (drv_data->tx)));
283a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->tx += 2;
28493b61bddc13d9acf1fe341b39d826e80f3182d1eWolfgang Muees		/* wait until transfer finished.
28593b61bddc13d9acf1fe341b39d826e80f3182d1eWolfgang Muees		   checking SPIF or TXS may not guarantee transfer completion */
28647885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger		while (!(bfin_read(&drv_data->regs->stat) & BIT_STAT_RXS))
28793b61bddc13d9acf1fe341b39d826e80f3182d1eWolfgang Muees			cpu_relax();
28893b61bddc13d9acf1fe341b39d826e80f3182d1eWolfgang Muees		/* discard RX data and clear RXS */
28993b61bddc13d9acf1fe341b39d826e80f3182d1eWolfgang Muees		bfin_spi_dummy_read(drv_data);
290a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
291a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
292a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
2939c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysingerstatic void bfin_spi_u16_reader(struct bfin_spi_master_data *drv_data)
294a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
29593b61bddc13d9acf1fe341b39d826e80f3182d1eWolfgang Muees	u16 tx_val = drv_data->cur_chip->idle_tx_val;
296cc487e732089360727e60f9fdbe3ff6cc4ca3155Sonic Zhang
29793b61bddc13d9acf1fe341b39d826e80f3182d1eWolfgang Muees	/* discard old RX data and clear RXS */
298138f97cd06deddd53ad496ac1656917a7b486d24Mike Frysinger	bfin_spi_dummy_read(drv_data);
299a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
30093b61bddc13d9acf1fe341b39d826e80f3182d1eWolfgang Muees	while (drv_data->rx < drv_data->rx_end) {
30147885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger		bfin_write(&drv_data->regs->tdbr, tx_val);
30247885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger		while (!(bfin_read(&drv_data->regs->stat) & BIT_STAT_RXS))
303d8c05008b0e464c94967ed2f20d1d661fca6790eBryan Wu			cpu_relax();
30447885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger		*(u16 *) (drv_data->rx) = bfin_read(&drv_data->regs->rdbr);
305a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->rx += 2;
306a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
307a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
308a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
3099c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysingerstatic void bfin_spi_u16_duplex(struct bfin_spi_master_data *drv_data)
310a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
31193b61bddc13d9acf1fe341b39d826e80f3182d1eWolfgang Muees	/* discard old RX data and clear RXS */
31293b61bddc13d9acf1fe341b39d826e80f3182d1eWolfgang Muees	bfin_spi_dummy_read(drv_data);
31393b61bddc13d9acf1fe341b39d826e80f3182d1eWolfgang Muees
31493b61bddc13d9acf1fe341b39d826e80f3182d1eWolfgang Muees	while (drv_data->rx < drv_data->rx_end) {
31547885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger		bfin_write(&drv_data->regs->tdbr, (*(u16 *) (drv_data->tx)));
31693b61bddc13d9acf1fe341b39d826e80f3182d1eWolfgang Muees		drv_data->tx += 2;
31747885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger		while (!(bfin_read(&drv_data->regs->stat) & BIT_STAT_RXS))
318d8c05008b0e464c94967ed2f20d1d661fca6790eBryan Wu			cpu_relax();
31947885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger		*(u16 *) (drv_data->rx) = bfin_read(&drv_data->regs->rdbr);
320a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->rx += 2;
321a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
322a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
323a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
3249c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysingerstatic const struct bfin_spi_transfer_ops bfin_bfin_spi_transfer_ops_u16 = {
3259c4542c7a3082bf74f00145355ef407ac82c0b3fMike Frysinger	.write  = bfin_spi_u16_writer,
3269c4542c7a3082bf74f00145355ef407ac82c0b3fMike Frysinger	.read   = bfin_spi_u16_reader,
3279c4542c7a3082bf74f00145355ef407ac82c0b3fMike Frysinger	.duplex = bfin_spi_u16_duplex,
3289c4542c7a3082bf74f00145355ef407ac82c0b3fMike Frysinger};
3299c4542c7a3082bf74f00145355ef407ac82c0b3fMike Frysinger
330e35954053c1a2ede37f6ed1b28d626dba43dc79dRob Maris/* test if there is more transfer to be done */
3319c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysingerstatic void *bfin_spi_next_transfer(struct bfin_spi_master_data *drv_data)
332a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
333a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct spi_message *msg = drv_data->cur_msg;
334a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct spi_transfer *trans = drv_data->cur_transfer;
335a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
336a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Move to next transfer */
337a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (trans->transfer_list.next != &msg->transfers) {
338a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->cur_transfer =
339a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		    list_entry(trans->transfer_list.next,
340a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			       struct spi_transfer, transfer_list);
341a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return RUNNING_STATE;
342a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	} else
343a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return DONE_STATE;
344a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
345a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
346a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan/*
347a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan * caller already set message->status;
348a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan * dma and pio irqs are blocked give finished message back
349a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan */
3509c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysingerstatic void bfin_spi_giveback(struct bfin_spi_master_data *drv_data)
351a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
3529c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysinger	struct bfin_spi_slave_data *chip = drv_data->cur_chip;
353a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct spi_transfer *last_transfer;
354a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	unsigned long flags;
355a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct spi_message *msg;
356a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
357a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	spin_lock_irqsave(&drv_data->lock, flags);
358a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	msg = drv_data->cur_msg;
359a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->cur_msg = NULL;
360a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->cur_transfer = NULL;
361a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->cur_chip = NULL;
362a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	queue_work(drv_data->workqueue, &drv_data->pump_messages);
363a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	spin_unlock_irqrestore(&drv_data->lock, flags);
364a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
365a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	last_transfer = list_entry(msg->transfers.prev,
366a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan				   struct spi_transfer, transfer_list);
367a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
368a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	msg->state = NULL;
369a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
370fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu	if (!drv_data->cs_change)
371138f97cd06deddd53ad496ac1656917a7b486d24Mike Frysinger		bfin_spi_cs_deactive(drv_data, chip);
372fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu
373b9b2a76a4391cadb6d42da2ccf5e956c459acb72Yi Li	/* Not stop spi in autobuffer mode */
374b9b2a76a4391cadb6d42da2ccf5e956c459acb72Yi Li	if (drv_data->tx_dma != 0xFFFF)
375b9b2a76a4391cadb6d42da2ccf5e956c459acb72Yi Li		bfin_spi_disable(drv_data);
376b9b2a76a4391cadb6d42da2ccf5e956c459acb72Yi Li
377a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (msg->complete)
378a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		msg->complete(msg->context);
379a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
380a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
381f6a6d96685be6e784849d067b44acb831f595417Yi Li/* spi data irq handler */
382f6a6d96685be6e784849d067b44acb831f595417Yi Listatic irqreturn_t bfin_spi_pio_irq_handler(int irq, void *dev_id)
383f6a6d96685be6e784849d067b44acb831f595417Yi Li{
3849c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysinger	struct bfin_spi_master_data *drv_data = dev_id;
3859c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysinger	struct bfin_spi_slave_data *chip = drv_data->cur_chip;
386f6a6d96685be6e784849d067b44acb831f595417Yi Li	struct spi_message *msg = drv_data->cur_msg;
387f6a6d96685be6e784849d067b44acb831f595417Yi Li	int n_bytes = drv_data->n_bytes;
3884d676fc5c39a677aa72148debd47029d8d8f0634Bob Liu	int loop = 0;
389f6a6d96685be6e784849d067b44acb831f595417Yi Li
390f6a6d96685be6e784849d067b44acb831f595417Yi Li	/* wait until transfer finished. */
39147885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger	while (!(bfin_read(&drv_data->regs->stat) & BIT_STAT_RXS))
392f6a6d96685be6e784849d067b44acb831f595417Yi Li		cpu_relax();
393f6a6d96685be6e784849d067b44acb831f595417Yi Li
394f6a6d96685be6e784849d067b44acb831f595417Yi Li	if ((drv_data->tx && drv_data->tx >= drv_data->tx_end) ||
395f6a6d96685be6e784849d067b44acb831f595417Yi Li		(drv_data->rx && drv_data->rx >= (drv_data->rx_end - n_bytes))) {
396f6a6d96685be6e784849d067b44acb831f595417Yi Li		/* last read */
397f6a6d96685be6e784849d067b44acb831f595417Yi Li		if (drv_data->rx) {
398f6a6d96685be6e784849d067b44acb831f595417Yi Li			dev_dbg(&drv_data->pdev->dev, "last read\n");
399128465ca7c0775609b1c24f66cd6bddac5f59c9bScott Jiang			if (!(n_bytes % 2)) {
4004d676fc5c39a677aa72148debd47029d8d8f0634Bob Liu				u16 *buf = (u16 *)drv_data->rx;
4014d676fc5c39a677aa72148debd47029d8d8f0634Bob Liu				for (loop = 0; loop < n_bytes / 2; loop++)
40247885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger					*buf++ = bfin_read(&drv_data->regs->rdbr);
4034d676fc5c39a677aa72148debd47029d8d8f0634Bob Liu			} else {
4044d676fc5c39a677aa72148debd47029d8d8f0634Bob Liu				u8 *buf = (u8 *)drv_data->rx;
4054d676fc5c39a677aa72148debd47029d8d8f0634Bob Liu				for (loop = 0; loop < n_bytes; loop++)
40647885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger					*buf++ = bfin_read(&drv_data->regs->rdbr);
4074d676fc5c39a677aa72148debd47029d8d8f0634Bob Liu			}
408f6a6d96685be6e784849d067b44acb831f595417Yi Li			drv_data->rx += n_bytes;
409f6a6d96685be6e784849d067b44acb831f595417Yi Li		}
410f6a6d96685be6e784849d067b44acb831f595417Yi Li
411f6a6d96685be6e784849d067b44acb831f595417Yi Li		msg->actual_length += drv_data->len_in_bytes;
412f6a6d96685be6e784849d067b44acb831f595417Yi Li		if (drv_data->cs_change)
413f6a6d96685be6e784849d067b44acb831f595417Yi Li			bfin_spi_cs_deactive(drv_data, chip);
414f6a6d96685be6e784849d067b44acb831f595417Yi Li		/* Move to next transfer */
415f6a6d96685be6e784849d067b44acb831f595417Yi Li		msg->state = bfin_spi_next_transfer(drv_data);
416f6a6d96685be6e784849d067b44acb831f595417Yi Li
4177370ed6b91c37d7022a89a820b0fcd3156fa87fcYi Li		disable_irq_nosync(drv_data->spi_irq);
418f6a6d96685be6e784849d067b44acb831f595417Yi Li
419f6a6d96685be6e784849d067b44acb831f595417Yi Li		/* Schedule transfer tasklet */
420f6a6d96685be6e784849d067b44acb831f595417Yi Li		tasklet_schedule(&drv_data->pump_transfers);
421f6a6d96685be6e784849d067b44acb831f595417Yi Li		return IRQ_HANDLED;
422f6a6d96685be6e784849d067b44acb831f595417Yi Li	}
423f6a6d96685be6e784849d067b44acb831f595417Yi Li
424f6a6d96685be6e784849d067b44acb831f595417Yi Li	if (drv_data->rx && drv_data->tx) {
425f6a6d96685be6e784849d067b44acb831f595417Yi Li		/* duplex */
426f6a6d96685be6e784849d067b44acb831f595417Yi Li		dev_dbg(&drv_data->pdev->dev, "duplex: write_TDBR\n");
427128465ca7c0775609b1c24f66cd6bddac5f59c9bScott Jiang		if (!(n_bytes % 2)) {
4284d676fc5c39a677aa72148debd47029d8d8f0634Bob Liu			u16 *buf = (u16 *)drv_data->rx;
4294d676fc5c39a677aa72148debd47029d8d8f0634Bob Liu			u16 *buf2 = (u16 *)drv_data->tx;
4304d676fc5c39a677aa72148debd47029d8d8f0634Bob Liu			for (loop = 0; loop < n_bytes / 2; loop++) {
43147885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger				*buf++ = bfin_read(&drv_data->regs->rdbr);
43247885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger				bfin_write(&drv_data->regs->tdbr, *buf2++);
4334d676fc5c39a677aa72148debd47029d8d8f0634Bob Liu			}
4344d676fc5c39a677aa72148debd47029d8d8f0634Bob Liu		} else {
4354d676fc5c39a677aa72148debd47029d8d8f0634Bob Liu			u8 *buf = (u8 *)drv_data->rx;
4364d676fc5c39a677aa72148debd47029d8d8f0634Bob Liu			u8 *buf2 = (u8 *)drv_data->tx;
4374d676fc5c39a677aa72148debd47029d8d8f0634Bob Liu			for (loop = 0; loop < n_bytes; loop++) {
43847885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger				*buf++ = bfin_read(&drv_data->regs->rdbr);
43947885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger				bfin_write(&drv_data->regs->tdbr, *buf2++);
4404d676fc5c39a677aa72148debd47029d8d8f0634Bob Liu			}
441f6a6d96685be6e784849d067b44acb831f595417Yi Li		}
442f6a6d96685be6e784849d067b44acb831f595417Yi Li	} else if (drv_data->rx) {
443f6a6d96685be6e784849d067b44acb831f595417Yi Li		/* read */
444f6a6d96685be6e784849d067b44acb831f595417Yi Li		dev_dbg(&drv_data->pdev->dev, "read: write_TDBR\n");
445128465ca7c0775609b1c24f66cd6bddac5f59c9bScott Jiang		if (!(n_bytes % 2)) {
4464d676fc5c39a677aa72148debd47029d8d8f0634Bob Liu			u16 *buf = (u16 *)drv_data->rx;
4474d676fc5c39a677aa72148debd47029d8d8f0634Bob Liu			for (loop = 0; loop < n_bytes / 2; loop++) {
44847885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger				*buf++ = bfin_read(&drv_data->regs->rdbr);
44947885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger				bfin_write(&drv_data->regs->tdbr, chip->idle_tx_val);
4504d676fc5c39a677aa72148debd47029d8d8f0634Bob Liu			}
4514d676fc5c39a677aa72148debd47029d8d8f0634Bob Liu		} else {
4524d676fc5c39a677aa72148debd47029d8d8f0634Bob Liu			u8 *buf = (u8 *)drv_data->rx;
4534d676fc5c39a677aa72148debd47029d8d8f0634Bob Liu			for (loop = 0; loop < n_bytes; loop++) {
45447885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger				*buf++ = bfin_read(&drv_data->regs->rdbr);
45547885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger				bfin_write(&drv_data->regs->tdbr, chip->idle_tx_val);
4564d676fc5c39a677aa72148debd47029d8d8f0634Bob Liu			}
4574d676fc5c39a677aa72148debd47029d8d8f0634Bob Liu		}
458f6a6d96685be6e784849d067b44acb831f595417Yi Li	} else if (drv_data->tx) {
459f6a6d96685be6e784849d067b44acb831f595417Yi Li		/* write */
460f6a6d96685be6e784849d067b44acb831f595417Yi Li		dev_dbg(&drv_data->pdev->dev, "write: write_TDBR\n");
461128465ca7c0775609b1c24f66cd6bddac5f59c9bScott Jiang		if (!(n_bytes % 2)) {
4624d676fc5c39a677aa72148debd47029d8d8f0634Bob Liu			u16 *buf = (u16 *)drv_data->tx;
4634d676fc5c39a677aa72148debd47029d8d8f0634Bob Liu			for (loop = 0; loop < n_bytes / 2; loop++) {
46447885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger				bfin_read(&drv_data->regs->rdbr);
46547885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger				bfin_write(&drv_data->regs->tdbr, *buf++);
4664d676fc5c39a677aa72148debd47029d8d8f0634Bob Liu			}
4674d676fc5c39a677aa72148debd47029d8d8f0634Bob Liu		} else {
4684d676fc5c39a677aa72148debd47029d8d8f0634Bob Liu			u8 *buf = (u8 *)drv_data->tx;
4694d676fc5c39a677aa72148debd47029d8d8f0634Bob Liu			for (loop = 0; loop < n_bytes; loop++) {
47047885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger				bfin_read(&drv_data->regs->rdbr);
47147885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger				bfin_write(&drv_data->regs->tdbr, *buf++);
4724d676fc5c39a677aa72148debd47029d8d8f0634Bob Liu			}
4734d676fc5c39a677aa72148debd47029d8d8f0634Bob Liu		}
474f6a6d96685be6e784849d067b44acb831f595417Yi Li	}
475f6a6d96685be6e784849d067b44acb831f595417Yi Li
476f6a6d96685be6e784849d067b44acb831f595417Yi Li	if (drv_data->tx)
477f6a6d96685be6e784849d067b44acb831f595417Yi Li		drv_data->tx += n_bytes;
478f6a6d96685be6e784849d067b44acb831f595417Yi Li	if (drv_data->rx)
479f6a6d96685be6e784849d067b44acb831f595417Yi Li		drv_data->rx += n_bytes;
480f6a6d96685be6e784849d067b44acb831f595417Yi Li
481f6a6d96685be6e784849d067b44acb831f595417Yi Li	return IRQ_HANDLED;
482f6a6d96685be6e784849d067b44acb831f595417Yi Li}
483f6a6d96685be6e784849d067b44acb831f595417Yi Li
484138f97cd06deddd53ad496ac1656917a7b486d24Mike Frysingerstatic irqreturn_t bfin_spi_dma_irq_handler(int irq, void *dev_id)
485a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
4869c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysinger	struct bfin_spi_master_data *drv_data = dev_id;
4879c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysinger	struct bfin_spi_slave_data *chip = drv_data->cur_chip;
488bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	struct spi_message *msg = drv_data->cur_msg;
489aaaf939c573b783398b6af863576322256352f64Mike Frysinger	unsigned long timeout;
490d24bd1d0dc850e7aa68c27ec288eb699d41a5916Mike Frysinger	unsigned short dmastat = get_dma_curr_irqstat(drv_data->dma_channel);
49147885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger	u16 spistat = bfin_read(&drv_data->regs->stat);
492a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
493d24bd1d0dc850e7aa68c27ec288eb699d41a5916Mike Frysinger	dev_dbg(&drv_data->pdev->dev,
494d24bd1d0dc850e7aa68c27ec288eb699d41a5916Mike Frysinger		"in dma_irq_handler dmastat:0x%x spistat:0x%x\n",
495d24bd1d0dc850e7aa68c27ec288eb699d41a5916Mike Frysinger		dmastat, spistat);
496d24bd1d0dc850e7aa68c27ec288eb699d41a5916Mike Frysinger
497782a895693a52fd8b288c33bdd7e98357888fc1fMichael Hennerich	if (drv_data->rx != NULL) {
49847885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger		u16 cr = bfin_read(&drv_data->regs->ctl);
499782a895693a52fd8b288c33bdd7e98357888fc1fMichael Hennerich		/* discard old RX data and clear RXS */
500782a895693a52fd8b288c33bdd7e98357888fc1fMichael Hennerich		bfin_spi_dummy_read(drv_data);
50147885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger		bfin_write(&drv_data->regs->ctl, cr & ~BIT_CTL_ENABLE); /* Disable SPI */
50247885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger		bfin_write(&drv_data->regs->ctl, cr & ~BIT_CTL_TIMOD); /* Restore State */
50347885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger		bfin_write(&drv_data->regs->stat, BIT_STAT_CLR); /* Clear Status */
504782a895693a52fd8b288c33bdd7e98357888fc1fMichael Hennerich	}
505782a895693a52fd8b288c33bdd7e98357888fc1fMichael Hennerich
506bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu	clear_dma_irqstat(drv_data->dma_channel);
507a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
508a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/*
509d6fe89b0630080e2bd6ece20ff7b1b5c2647ed62Bryan Wu	 * wait for the last transaction shifted out.  HRM states:
510d6fe89b0630080e2bd6ece20ff7b1b5c2647ed62Bryan Wu	 * at this point there may still be data in the SPI DMA FIFO waiting
511d6fe89b0630080e2bd6ece20ff7b1b5c2647ed62Bryan Wu	 * to be transmitted ... software needs to poll TXS in the SPI_STAT
512d6fe89b0630080e2bd6ece20ff7b1b5c2647ed62Bryan Wu	 * register until it goes low for 2 successive reads
513a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	 */
514a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (drv_data->tx != NULL) {
51547885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger		while ((bfin_read(&drv_data->regs->stat) & BIT_STAT_TXS) ||
51647885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger		       (bfin_read(&drv_data->regs->stat) & BIT_STAT_TXS))
517d8c05008b0e464c94967ed2f20d1d661fca6790eBryan Wu			cpu_relax();
518a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
519a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
520aaaf939c573b783398b6af863576322256352f64Mike Frysinger	dev_dbg(&drv_data->pdev->dev,
521aaaf939c573b783398b6af863576322256352f64Mike Frysinger		"in dma_irq_handler dmastat:0x%x spistat:0x%x\n",
52247885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger		dmastat, bfin_read(&drv_data->regs->stat));
523aaaf939c573b783398b6af863576322256352f64Mike Frysinger
524aaaf939c573b783398b6af863576322256352f64Mike Frysinger	timeout = jiffies + HZ;
52547885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger	while (!(bfin_read(&drv_data->regs->stat) & BIT_STAT_SPIF))
526aaaf939c573b783398b6af863576322256352f64Mike Frysinger		if (!time_before(jiffies, timeout)) {
527aaaf939c573b783398b6af863576322256352f64Mike Frysinger			dev_warn(&drv_data->pdev->dev, "timeout waiting for SPIF");
528aaaf939c573b783398b6af863576322256352f64Mike Frysinger			break;
529aaaf939c573b783398b6af863576322256352f64Mike Frysinger		} else
530aaaf939c573b783398b6af863576322256352f64Mike Frysinger			cpu_relax();
531a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
53290008a641dd832cc2e2c4d21b7da94de91e9d0a4Mike Frysinger	if ((dmastat & DMA_ERR) && (spistat & BIT_STAT_RBSY)) {
53304b95d2f7453d64f89ca1d8c3e70bcc7cc38320fMike Frysinger		msg->state = ERROR_STATE;
53404b95d2f7453d64f89ca1d8c3e70bcc7cc38320fMike Frysinger		dev_err(&drv_data->pdev->dev, "dma receive: fifo/buffer overflow\n");
53504b95d2f7453d64f89ca1d8c3e70bcc7cc38320fMike Frysinger	} else {
53604b95d2f7453d64f89ca1d8c3e70bcc7cc38320fMike Frysinger		msg->actual_length += drv_data->len_in_bytes;
537a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
53804b95d2f7453d64f89ca1d8c3e70bcc7cc38320fMike Frysinger		if (drv_data->cs_change)
539138f97cd06deddd53ad496ac1656917a7b486d24Mike Frysinger			bfin_spi_cs_deactive(drv_data, chip);
540fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu
54104b95d2f7453d64f89ca1d8c3e70bcc7cc38320fMike Frysinger		/* Move to next transfer */
542138f97cd06deddd53ad496ac1656917a7b486d24Mike Frysinger		msg->state = bfin_spi_next_transfer(drv_data);
54304b95d2f7453d64f89ca1d8c3e70bcc7cc38320fMike Frysinger	}
544a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
545a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Schedule transfer tasklet */
546a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	tasklet_schedule(&drv_data->pump_transfers);
547a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
548a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* free the irq handler before next transfer */
54988b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu	dev_dbg(&drv_data->pdev->dev,
55088b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu		"disable dma channel irq%d\n",
551bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		drv_data->dma_channel);
552a75bd65b2189d711938d0fa7d9a79df47ddd66faBarry Song	dma_disable_irq_nosync(drv_data->dma_channel);
553a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
554a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	return IRQ_HANDLED;
555a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
556a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
557138f97cd06deddd53ad496ac1656917a7b486d24Mike Frysingerstatic void bfin_spi_pump_transfers(unsigned long data)
558a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
5599c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysinger	struct bfin_spi_master_data *drv_data = (struct bfin_spi_master_data *)data;
560a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct spi_message *message = NULL;
561a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct spi_transfer *transfer = NULL;
562a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct spi_transfer *previous = NULL;
5639c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysinger	struct bfin_spi_slave_data *chip = NULL;
564033f44bd0ebca1809e8274237a64263d909f01a7Mike Frysinger	unsigned int bits_per_word;
5655e8592dca303fb429d1641c205fe509f4b781ca2Mike Frysinger	u16 cr, cr_width, dma_width, dma_config;
566a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	u32 tranf_success = 1;
5678eeb12e5a2486ab958fa27ec97e71dabf234b73bVitja Makarov	u8 full_duplex = 0;
568a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
569a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Get current state information */
570a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	message = drv_data->cur_msg;
571a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	transfer = drv_data->cur_transfer;
572a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	chip = drv_data->cur_chip;
573092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu
574a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/*
575a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	 * if msg is error or done, report it back using complete() callback
576a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	 */
577a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
578a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	 /* Handle for abort */
579a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (message->state == ERROR_STATE) {
580d24bd1d0dc850e7aa68c27ec288eb699d41a5916Mike Frysinger		dev_dbg(&drv_data->pdev->dev, "transfer: we've hit an error\n");
581a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		message->status = -EIO;
582138f97cd06deddd53ad496ac1656917a7b486d24Mike Frysinger		bfin_spi_giveback(drv_data);
583a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return;
584a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
585a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
586a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Handle end of message */
587a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (message->state == DONE_STATE) {
588d24bd1d0dc850e7aa68c27ec288eb699d41a5916Mike Frysinger		dev_dbg(&drv_data->pdev->dev, "transfer: all done!\n");
589a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		message->status = 0;
5902431a8154634027ce3915200699f26fb3725a1f2Scott Jiang		bfin_spi_flush(drv_data);
591138f97cd06deddd53ad496ac1656917a7b486d24Mike Frysinger		bfin_spi_giveback(drv_data);
592a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return;
593a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
594a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
595a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Delay if requested at end of transfer */
596a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (message->state == RUNNING_STATE) {
597d24bd1d0dc850e7aa68c27ec288eb699d41a5916Mike Frysinger		dev_dbg(&drv_data->pdev->dev, "transfer: still running ...\n");
598a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		previous = list_entry(transfer->transfer_list.prev,
599a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan				      struct spi_transfer, transfer_list);
600a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		if (previous->delay_usecs)
601a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			udelay(previous->delay_usecs);
602a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
603a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
604ab09e0406ffd42d26fc9a6dcbb626f9eb1da9160Mike Frysinger	/* Flush any existing transfers that may be sitting in the hardware */
605138f97cd06deddd53ad496ac1656917a7b486d24Mike Frysinger	if (bfin_spi_flush(drv_data) == 0) {
606a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		dev_err(&drv_data->pdev->dev, "pump_transfers: flush failed\n");
607a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		message->status = -EIO;
608138f97cd06deddd53ad496ac1656917a7b486d24Mike Frysinger		bfin_spi_giveback(drv_data);
609a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return;
610a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
611a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
61293b61bddc13d9acf1fe341b39d826e80f3182d1eWolfgang Muees	if (transfer->len == 0) {
61393b61bddc13d9acf1fe341b39d826e80f3182d1eWolfgang Muees		/* Move to next transfer of this msg */
61493b61bddc13d9acf1fe341b39d826e80f3182d1eWolfgang Muees		message->state = bfin_spi_next_transfer(drv_data);
61593b61bddc13d9acf1fe341b39d826e80f3182d1eWolfgang Muees		/* Schedule next transfer tasklet */
61693b61bddc13d9acf1fe341b39d826e80f3182d1eWolfgang Muees		tasklet_schedule(&drv_data->pump_transfers);
6171974eba605557e934764cb83c8ceb0eca78f011aSonic Zhang		return;
61893b61bddc13d9acf1fe341b39d826e80f3182d1eWolfgang Muees	}
61993b61bddc13d9acf1fe341b39d826e80f3182d1eWolfgang Muees
620a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (transfer->tx_buf != NULL) {
621a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->tx = (void *)transfer->tx_buf;
622a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->tx_end = drv_data->tx + transfer->len;
62388b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu		dev_dbg(&drv_data->pdev->dev, "tx_buf is %p, tx_end is %p\n",
62488b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu			transfer->tx_buf, drv_data->tx_end);
625a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	} else {
626a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->tx = NULL;
627a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
628a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
629a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (transfer->rx_buf != NULL) {
6308eeb12e5a2486ab958fa27ec97e71dabf234b73bVitja Makarov		full_duplex = transfer->tx_buf != NULL;
631a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->rx = transfer->rx_buf;
632a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->rx_end = drv_data->rx + transfer->len;
63388b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu		dev_dbg(&drv_data->pdev->dev, "rx_buf is %p, rx_end is %p\n",
63488b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu			transfer->rx_buf, drv_data->rx_end);
635a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	} else {
636a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->rx = NULL;
637a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
638a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
639a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->rx_dma = transfer->rx_dma;
640a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->tx_dma = transfer->tx_dma;
641a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->len_in_bytes = transfer->len;
642fad91c890909aabab0d9858d50f3c8394ee16b21Bryan Wu	drv_data->cs_change = transfer->cs_change;
643a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
644092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu	/* Bits per word setup */
645e479c60456ef22b0869432887216186aabaed086Mike Frysinger	bits_per_word = transfer->bits_per_word ? :
646e479c60456ef22b0869432887216186aabaed086Mike Frysinger		message->spi->bits_per_word ? : 8;
647e479c60456ef22b0869432887216186aabaed086Mike Frysinger	if (bits_per_word % 16 == 0) {
6484d676fc5c39a677aa72148debd47029d8d8f0634Bob Liu		drv_data->n_bytes = bits_per_word/8;
6495e8592dca303fb429d1641c205fe509f4b781ca2Mike Frysinger		drv_data->len = (transfer->len) >> 1;
6505e8592dca303fb429d1641c205fe509f4b781ca2Mike Frysinger		cr_width = BIT_CTL_WORDSIZE;
6519c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysinger		drv_data->ops = &bfin_bfin_spi_transfer_ops_u16;
652e479c60456ef22b0869432887216186aabaed086Mike Frysinger	} else if (bits_per_word % 8 == 0) {
6534d676fc5c39a677aa72148debd47029d8d8f0634Bob Liu		drv_data->n_bytes = bits_per_word/8;
6544d676fc5c39a677aa72148debd47029d8d8f0634Bob Liu		drv_data->len = transfer->len;
6554d676fc5c39a677aa72148debd47029d8d8f0634Bob Liu		cr_width = 0;
6564d676fc5c39a677aa72148debd47029d8d8f0634Bob Liu		drv_data->ops = &bfin_bfin_spi_transfer_ops_u8;
6572e768659df35ea337cb57ea3573c918d31e07894Bob Liu	} else {
6582e768659df35ea337cb57ea3573c918d31e07894Bob Liu		dev_err(&drv_data->pdev->dev, "transfer: unsupported bits_per_word\n");
6592e768659df35ea337cb57ea3573c918d31e07894Bob Liu		message->status = -EINVAL;
6602e768659df35ea337cb57ea3573c918d31e07894Bob Liu		bfin_spi_giveback(drv_data);
6612e768659df35ea337cb57ea3573c918d31e07894Bob Liu		return;
662092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu	}
66347885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger	cr = bfin_read(&drv_data->regs->ctl) & ~(BIT_CTL_TIMOD | BIT_CTL_WORDSIZE);
6645e8592dca303fb429d1641c205fe509f4b781ca2Mike Frysinger	cr |= cr_width;
66547885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger	bfin_write(&drv_data->regs->ctl, cr);
666092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu
6674fb98efacffd3dfbe8e3b9cb054dd71bab715065Mike Frysinger	dev_dbg(&drv_data->pdev->dev,
6689c4542c7a3082bf74f00145355ef407ac82c0b3fMike Frysinger		"transfer: drv_data->ops is %p, chip->ops is %p, u8_ops is %p\n",
6699c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysinger		drv_data->ops, chip->ops, &bfin_bfin_spi_transfer_ops_u8);
670a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
671a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	message->state = RUNNING_STATE;
672a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	dma_config = 0;
673a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
674092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu	/* Speed setup (surely valid because already checked) */
675092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu	if (transfer->speed_hz)
67647885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger		bfin_write(&drv_data->regs->baud, hz_to_spi_baud(transfer->speed_hz));
677092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu	else
67847885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger		bfin_write(&drv_data->regs->baud, chip->baud);
679092e1fdaf35126475aef0dc70f4a2ce4f2f43052Bryan Wu
68047885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger	bfin_write(&drv_data->regs->stat, BIT_STAT_CLR);
681e72dcde72c712708e2145ab0ecff539ff4a4c7fbRob Maris	bfin_spi_cs_active(drv_data, chip);
682a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
68388b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu	dev_dbg(&drv_data->pdev->dev,
68488b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu		"now pumping a transfer: width is %d, len is %d\n",
6855e8592dca303fb429d1641c205fe509f4b781ca2Mike Frysinger		cr_width, transfer->len);
686a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
687a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/*
6888cf5858c51f88208fe56b195251ab4f21265386cVitja Makarov	 * Try to map dma buffer and do a dma transfer.  If successful use,
6898cf5858c51f88208fe56b195251ab4f21265386cVitja Makarov	 * different way to r/w according to the enable_dma settings and if
6908cf5858c51f88208fe56b195251ab4f21265386cVitja Makarov	 * we are not doing a full duplex transfer (since the hardware does
6918cf5858c51f88208fe56b195251ab4f21265386cVitja Makarov	 * not support full duplex DMA transfers).
692a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	 */
6938eeb12e5a2486ab958fa27ec97e71dabf234b73bVitja Makarov	if (!full_duplex && drv_data->cur_chip->enable_dma
6948eeb12e5a2486ab958fa27ec97e71dabf234b73bVitja Makarov				&& drv_data->len > 6) {
695a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
69611d6f5995137ba4dc49e9337185ac0a8753f8f69Mike Frysinger		unsigned long dma_start_addr, flags;
6977aec35661733c651f616f9b3f69d758f6bfe2a7fMike Frysinger
698bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		disable_dma(drv_data->dma_channel);
699bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		clear_dma_irqstat(drv_data->dma_channel);
700a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
701a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		/* config dma channel */
70288b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu		dev_dbg(&drv_data->pdev->dev, "doing dma transfer\n");
7037aec35661733c651f616f9b3f69d758f6bfe2a7fMike Frysinger		set_dma_x_count(drv_data->dma_channel, drv_data->len);
7045e8592dca303fb429d1641c205fe509f4b781ca2Mike Frysinger		if (cr_width == BIT_CTL_WORDSIZE) {
705bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu			set_dma_x_modify(drv_data->dma_channel, 2);
706a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			dma_width = WDSIZE_16;
707a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		} else {
708bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu			set_dma_x_modify(drv_data->dma_channel, 1);
709a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			dma_width = WDSIZE_8;
710a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		}
711a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
7123f479a65b3f49ee4f058a965e6e33d97ee467b68Sonic Zhang		/* poll for SPI completion before start */
71347885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger		while (!(bfin_read(&drv_data->regs->stat) & BIT_STAT_SPIF))
714d8c05008b0e464c94967ed2f20d1d661fca6790eBryan Wu			cpu_relax();
7153f479a65b3f49ee4f058a965e6e33d97ee467b68Sonic Zhang
716a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		/* dirty hack for autobuffer DMA mode */
717a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		if (drv_data->tx_dma == 0xFFFF) {
71888b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu			dev_dbg(&drv_data->pdev->dev,
71988b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu				"doing autobuffer DMA out.\n");
720a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
721a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			/* no irq in autobuffer mode */
722a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			dma_config =
723a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			    (DMAFLOW_AUTO | RESTART | dma_width | DI_EN);
724bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu			set_dma_config(drv_data->dma_channel, dma_config);
725bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu			set_dma_start_addr(drv_data->dma_channel,
726a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu					(unsigned long)drv_data->tx);
727bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu			enable_dma(drv_data->dma_channel);
728a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
72907612e5f224613020c0ba17ce28e8eac052ef8ceSonic Zhang			/* start SPI transfer */
73047885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger			bfin_write(&drv_data->regs->ctl, cr | BIT_CTL_TIMOD_DMA_TX);
73107612e5f224613020c0ba17ce28e8eac052ef8ceSonic Zhang
73207612e5f224613020c0ba17ce28e8eac052ef8ceSonic Zhang			/* just return here, there can only be one transfer
73307612e5f224613020c0ba17ce28e8eac052ef8ceSonic Zhang			 * in this mode
73407612e5f224613020c0ba17ce28e8eac052ef8ceSonic Zhang			 */
735a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			message->status = 0;
736138f97cd06deddd53ad496ac1656917a7b486d24Mike Frysinger			bfin_spi_giveback(drv_data);
737a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			return;
738a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		}
739a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
740a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		/* In dma mode, rx or tx must be NULL in one transfer */
7417aec35661733c651f616f9b3f69d758f6bfe2a7fMike Frysinger		dma_config = (RESTART | dma_width | DI_EN);
742a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		if (drv_data->rx != NULL) {
743a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			/* set transfer mode, and enable SPI */
744d24bd1d0dc850e7aa68c27ec288eb699d41a5916Mike Frysinger			dev_dbg(&drv_data->pdev->dev, "doing DMA in to %p (size %zx)\n",
745d24bd1d0dc850e7aa68c27ec288eb699d41a5916Mike Frysinger				drv_data->rx, drv_data->len_in_bytes);
746a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
7478cf5858c51f88208fe56b195251ab4f21265386cVitja Makarov			/* invalidate caches, if needed */
74867834fa93d7a4fac9069a07e739110d3916d8cd4Jie Zhang			if (bfin_addr_dcacheable((unsigned long) drv_data->rx))
7498cf5858c51f88208fe56b195251ab4f21265386cVitja Makarov				invalidate_dcache_range((unsigned long) drv_data->rx,
7508cf5858c51f88208fe56b195251ab4f21265386cVitja Makarov							(unsigned long) (drv_data->rx +
751ace32865a3767e4e385b883868c228a2a6db225aMike Frysinger							drv_data->len_in_bytes));
7528cf5858c51f88208fe56b195251ab4f21265386cVitja Makarov
7537aec35661733c651f616f9b3f69d758f6bfe2a7fMike Frysinger			dma_config |= WNR;
7547aec35661733c651f616f9b3f69d758f6bfe2a7fMike Frysinger			dma_start_addr = (unsigned long)drv_data->rx;
755b31e27a6dc2c6534399c595ba78390125a56e90fMike Frysinger			cr |= BIT_CTL_TIMOD_DMA_RX | BIT_CTL_SENDOPT;
75607612e5f224613020c0ba17ce28e8eac052ef8ceSonic Zhang
757a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		} else if (drv_data->tx != NULL) {
75888b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu			dev_dbg(&drv_data->pdev->dev, "doing DMA out.\n");
759a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
7608cf5858c51f88208fe56b195251ab4f21265386cVitja Makarov			/* flush caches, if needed */
76167834fa93d7a4fac9069a07e739110d3916d8cd4Jie Zhang			if (bfin_addr_dcacheable((unsigned long) drv_data->tx))
7628cf5858c51f88208fe56b195251ab4f21265386cVitja Makarov				flush_dcache_range((unsigned long) drv_data->tx,
7638cf5858c51f88208fe56b195251ab4f21265386cVitja Makarov						(unsigned long) (drv_data->tx +
764ace32865a3767e4e385b883868c228a2a6db225aMike Frysinger						drv_data->len_in_bytes));
7658cf5858c51f88208fe56b195251ab4f21265386cVitja Makarov
7667aec35661733c651f616f9b3f69d758f6bfe2a7fMike Frysinger			dma_start_addr = (unsigned long)drv_data->tx;
767b31e27a6dc2c6534399c595ba78390125a56e90fMike Frysinger			cr |= BIT_CTL_TIMOD_DMA_TX;
7687aec35661733c651f616f9b3f69d758f6bfe2a7fMike Frysinger
7697aec35661733c651f616f9b3f69d758f6bfe2a7fMike Frysinger		} else
7707aec35661733c651f616f9b3f69d758f6bfe2a7fMike Frysinger			BUG();
7717aec35661733c651f616f9b3f69d758f6bfe2a7fMike Frysinger
77211d6f5995137ba4dc49e9337185ac0a8753f8f69Mike Frysinger		/* oh man, here there be monsters ... and i dont mean the
77311d6f5995137ba4dc49e9337185ac0a8753f8f69Mike Frysinger		 * fluffy cute ones from pixar, i mean the kind that'll eat
77411d6f5995137ba4dc49e9337185ac0a8753f8f69Mike Frysinger		 * your data, kick your dog, and love it all.  do *not* try
77511d6f5995137ba4dc49e9337185ac0a8753f8f69Mike Frysinger		 * and change these lines unless you (1) heavily test DMA
77611d6f5995137ba4dc49e9337185ac0a8753f8f69Mike Frysinger		 * with SPI flashes on a loaded system (e.g. ping floods),
77711d6f5995137ba4dc49e9337185ac0a8753f8f69Mike Frysinger		 * (2) know just how broken the DMA engine interaction with
77811d6f5995137ba4dc49e9337185ac0a8753f8f69Mike Frysinger		 * the SPI peripheral is, and (3) have someone else to blame
77911d6f5995137ba4dc49e9337185ac0a8753f8f69Mike Frysinger		 * when you screw it all up anyways.
78011d6f5995137ba4dc49e9337185ac0a8753f8f69Mike Frysinger		 */
7817aec35661733c651f616f9b3f69d758f6bfe2a7fMike Frysinger		set_dma_start_addr(drv_data->dma_channel, dma_start_addr);
78211d6f5995137ba4dc49e9337185ac0a8753f8f69Mike Frysinger		set_dma_config(drv_data->dma_channel, dma_config);
78311d6f5995137ba4dc49e9337185ac0a8753f8f69Mike Frysinger		local_irq_save(flags);
784a963ea83b316b0a3ebf1c7118a6c36b5cd334bb6Mike Frysinger		SSYNC();
78547885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger		bfin_write(&drv_data->regs->ctl, cr);
786a963ea83b316b0a3ebf1c7118a6c36b5cd334bb6Mike Frysinger		enable_dma(drv_data->dma_channel);
78711d6f5995137ba4dc49e9337185ac0a8753f8f69Mike Frysinger		dma_enable_irq(drv_data->dma_channel);
78811d6f5995137ba4dc49e9337185ac0a8753f8f69Mike Frysinger		local_irq_restore(flags);
78907612e5f224613020c0ba17ce28e8eac052ef8ceSonic Zhang
790f6a6d96685be6e784849d067b44acb831f595417Yi Li		return;
791f6a6d96685be6e784849d067b44acb831f595417Yi Li	}
792a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
7935e8592dca303fb429d1641c205fe509f4b781ca2Mike Frysinger	/*
7945e8592dca303fb429d1641c205fe509f4b781ca2Mike Frysinger	 * We always use SPI_WRITE mode (transfer starts with TDBR write).
7955e8592dca303fb429d1641c205fe509f4b781ca2Mike Frysinger	 * SPI_READ mode (transfer starts with RDBR read) seems to have
7965e8592dca303fb429d1641c205fe509f4b781ca2Mike Frysinger	 * problems with setting up the output value in TDBR prior to the
7975e8592dca303fb429d1641c205fe509f4b781ca2Mike Frysinger	 * start of the transfer.
7985e8592dca303fb429d1641c205fe509f4b781ca2Mike Frysinger	 */
79947885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger	bfin_write(&drv_data->regs->ctl, cr | BIT_CTL_TXMOD);
8005e8592dca303fb429d1641c205fe509f4b781ca2Mike Frysinger
801f6a6d96685be6e784849d067b44acb831f595417Yi Li	if (chip->pio_interrupt) {
8025e8592dca303fb429d1641c205fe509f4b781ca2Mike Frysinger		/* SPI irq should have been disabled by now */
80393b61bddc13d9acf1fe341b39d826e80f3182d1eWolfgang Muees
804f6a6d96685be6e784849d067b44acb831f595417Yi Li		/* discard old RX data and clear RXS */
805f6a6d96685be6e784849d067b44acb831f595417Yi Li		bfin_spi_dummy_read(drv_data);
806a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
807f6a6d96685be6e784849d067b44acb831f595417Yi Li		/* start transfer */
808f6a6d96685be6e784849d067b44acb831f595417Yi Li		if (drv_data->tx == NULL)
80947885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger			bfin_write(&drv_data->regs->tdbr, chip->idle_tx_val);
810f6a6d96685be6e784849d067b44acb831f595417Yi Li		else {
8114d676fc5c39a677aa72148debd47029d8d8f0634Bob Liu			int loop;
8124d676fc5c39a677aa72148debd47029d8d8f0634Bob Liu			if (bits_per_word % 16 == 0) {
8134d676fc5c39a677aa72148debd47029d8d8f0634Bob Liu				u16 *buf = (u16 *)drv_data->tx;
8144d676fc5c39a677aa72148debd47029d8d8f0634Bob Liu				for (loop = 0; loop < bits_per_word / 16;
8154d676fc5c39a677aa72148debd47029d8d8f0634Bob Liu						loop++) {
81647885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger					bfin_write(&drv_data->regs->tdbr, *buf++);
8174d676fc5c39a677aa72148debd47029d8d8f0634Bob Liu				}
8184d676fc5c39a677aa72148debd47029d8d8f0634Bob Liu			} else if (bits_per_word % 8 == 0) {
8194d676fc5c39a677aa72148debd47029d8d8f0634Bob Liu				u8 *buf = (u8 *)drv_data->tx;
8204d676fc5c39a677aa72148debd47029d8d8f0634Bob Liu				for (loop = 0; loop < bits_per_word / 8; loop++)
82147885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger					bfin_write(&drv_data->regs->tdbr, *buf++);
8224d676fc5c39a677aa72148debd47029d8d8f0634Bob Liu			}
8234d676fc5c39a677aa72148debd47029d8d8f0634Bob Liu
824f6a6d96685be6e784849d067b44acb831f595417Yi Li			drv_data->tx += drv_data->n_bytes;
825f6a6d96685be6e784849d067b44acb831f595417Yi Li		}
826a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
827f6a6d96685be6e784849d067b44acb831f595417Yi Li		/* once TDBR is empty, interrupt is triggered */
828f6a6d96685be6e784849d067b44acb831f595417Yi Li		enable_irq(drv_data->spi_irq);
829f6a6d96685be6e784849d067b44acb831f595417Yi Li		return;
830f6a6d96685be6e784849d067b44acb831f595417Yi Li	}
831a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
832f6a6d96685be6e784849d067b44acb831f595417Yi Li	/* IO mode */
833f6a6d96685be6e784849d067b44acb831f595417Yi Li	dev_dbg(&drv_data->pdev->dev, "doing IO transfer\n");
834f6a6d96685be6e784849d067b44acb831f595417Yi Li
835f6a6d96685be6e784849d067b44acb831f595417Yi Li	if (full_duplex) {
836f6a6d96685be6e784849d067b44acb831f595417Yi Li		/* full duplex mode */
837f6a6d96685be6e784849d067b44acb831f595417Yi Li		BUG_ON((drv_data->tx_end - drv_data->tx) !=
838f6a6d96685be6e784849d067b44acb831f595417Yi Li		       (drv_data->rx_end - drv_data->rx));
839f6a6d96685be6e784849d067b44acb831f595417Yi Li		dev_dbg(&drv_data->pdev->dev,
840f6a6d96685be6e784849d067b44acb831f595417Yi Li			"IO duplex: cr is 0x%x\n", cr);
841f6a6d96685be6e784849d067b44acb831f595417Yi Li
8429c4542c7a3082bf74f00145355ef407ac82c0b3fMike Frysinger		drv_data->ops->duplex(drv_data);
843f6a6d96685be6e784849d067b44acb831f595417Yi Li
844f6a6d96685be6e784849d067b44acb831f595417Yi Li		if (drv_data->tx != drv_data->tx_end)
845f6a6d96685be6e784849d067b44acb831f595417Yi Li			tranf_success = 0;
846f6a6d96685be6e784849d067b44acb831f595417Yi Li	} else if (drv_data->tx != NULL) {
847f6a6d96685be6e784849d067b44acb831f595417Yi Li		/* write only half duplex */
848f6a6d96685be6e784849d067b44acb831f595417Yi Li		dev_dbg(&drv_data->pdev->dev,
849f6a6d96685be6e784849d067b44acb831f595417Yi Li			"IO write: cr is 0x%x\n", cr);
850f6a6d96685be6e784849d067b44acb831f595417Yi Li
8519c4542c7a3082bf74f00145355ef407ac82c0b3fMike Frysinger		drv_data->ops->write(drv_data);
852f6a6d96685be6e784849d067b44acb831f595417Yi Li
853f6a6d96685be6e784849d067b44acb831f595417Yi Li		if (drv_data->tx != drv_data->tx_end)
854f6a6d96685be6e784849d067b44acb831f595417Yi Li			tranf_success = 0;
855f6a6d96685be6e784849d067b44acb831f595417Yi Li	} else if (drv_data->rx != NULL) {
856f6a6d96685be6e784849d067b44acb831f595417Yi Li		/* read only half duplex */
857f6a6d96685be6e784849d067b44acb831f595417Yi Li		dev_dbg(&drv_data->pdev->dev,
858f6a6d96685be6e784849d067b44acb831f595417Yi Li			"IO read: cr is 0x%x\n", cr);
859f6a6d96685be6e784849d067b44acb831f595417Yi Li
8609c4542c7a3082bf74f00145355ef407ac82c0b3fMike Frysinger		drv_data->ops->read(drv_data);
861f6a6d96685be6e784849d067b44acb831f595417Yi Li		if (drv_data->rx != drv_data->rx_end)
862f6a6d96685be6e784849d067b44acb831f595417Yi Li			tranf_success = 0;
863f6a6d96685be6e784849d067b44acb831f595417Yi Li	}
864a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
865f6a6d96685be6e784849d067b44acb831f595417Yi Li	if (!tranf_success) {
866f6a6d96685be6e784849d067b44acb831f595417Yi Li		dev_dbg(&drv_data->pdev->dev,
867f6a6d96685be6e784849d067b44acb831f595417Yi Li			"IO write error!\n");
868f6a6d96685be6e784849d067b44acb831f595417Yi Li		message->state = ERROR_STATE;
869f6a6d96685be6e784849d067b44acb831f595417Yi Li	} else {
87025985edcedea6396277003854657b5f3cb31a628Lucas De Marchi		/* Update total byte transferred */
871f6a6d96685be6e784849d067b44acb831f595417Yi Li		message->actual_length += drv_data->len_in_bytes;
872f6a6d96685be6e784849d067b44acb831f595417Yi Li		/* Move to next transfer of this msg */
873f6a6d96685be6e784849d067b44acb831f595417Yi Li		message->state = bfin_spi_next_transfer(drv_data);
8742431a8154634027ce3915200699f26fb3725a1f2Scott Jiang		if (drv_data->cs_change && message->state != DONE_STATE) {
8752431a8154634027ce3915200699f26fb3725a1f2Scott Jiang			bfin_spi_flush(drv_data);
876f6a6d96685be6e784849d067b44acb831f595417Yi Li			bfin_spi_cs_deactive(drv_data, chip);
8772431a8154634027ce3915200699f26fb3725a1f2Scott Jiang		}
878a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
879f6a6d96685be6e784849d067b44acb831f595417Yi Li
880f6a6d96685be6e784849d067b44acb831f595417Yi Li	/* Schedule next transfer tasklet */
881f6a6d96685be6e784849d067b44acb831f595417Yi Li	tasklet_schedule(&drv_data->pump_transfers);
882a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
883a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
884a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan/* pop a msg from queue and kick off real transfer */
885138f97cd06deddd53ad496ac1656917a7b486d24Mike Frysingerstatic void bfin_spi_pump_messages(struct work_struct *work)
886a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
8879c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysinger	struct bfin_spi_master_data *drv_data;
888a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	unsigned long flags;
889a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
8909c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysinger	drv_data = container_of(work, struct bfin_spi_master_data, pump_messages);
891131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu
892a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Lock queue and check for queue work */
893a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	spin_lock_irqsave(&drv_data->lock, flags);
894f4f50c3ff7815d83dcbb19341f35db2f408ac4f8Mike Frysinger	if (list_empty(&drv_data->queue) || !drv_data->running) {
895a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		/* pumper kicked off but no work to do */
896a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		drv_data->busy = 0;
897a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		spin_unlock_irqrestore(&drv_data->lock, flags);
898a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return;
899a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
900a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
901a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Make sure we are not already running a message */
902a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (drv_data->cur_msg) {
903a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		spin_unlock_irqrestore(&drv_data->lock, flags);
904a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return;
905a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
906a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
907a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Extract head of queue */
908a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->cur_msg = list_entry(drv_data->queue.next,
909a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan				       struct spi_message, queue);
9105fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu
9115fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu	/* Setup the SSP using the per chip configuration */
9125fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu	drv_data->cur_chip = spi_get_ctldata(drv_data->cur_msg->spi);
913138f97cd06deddd53ad496ac1656917a7b486d24Mike Frysinger	bfin_spi_restore_state(drv_data);
9145fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu
915a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	list_del_init(&drv_data->cur_msg->queue);
916a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
917a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Initial message state */
918a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->cur_msg->state = START_STATE;
919a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->cur_transfer = list_entry(drv_data->cur_msg->transfers.next,
920a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan					    struct spi_transfer, transfer_list);
921a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
9225fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu	dev_dbg(&drv_data->pdev->dev, "got a message to pump, "
9235fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu		"state is set to: baud %d, flag 0x%x, ctl 0x%x\n",
9245fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu		drv_data->cur_chip->baud, drv_data->cur_chip->flag,
9255fec5b5a4ec0d6d8b41c56e3cc7de41063cd4736Bryan Wu		drv_data->cur_chip->ctl_reg);
926131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu
927131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu	dev_dbg(&drv_data->pdev->dev,
92888b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu		"the first transfer len is %d\n",
92988b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu		drv_data->cur_transfer->len);
930a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
931a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Mark as busy and launch transfers */
932a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	tasklet_schedule(&drv_data->pump_transfers);
933a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
934a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->busy = 1;
935a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	spin_unlock_irqrestore(&drv_data->lock, flags);
936a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
937a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
938a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan/*
939a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan * got a msg to transfer, queue it in drv_data->queue.
940a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan * And kick off message pumper
941a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan */
942138f97cd06deddd53ad496ac1656917a7b486d24Mike Frysingerstatic int bfin_spi_transfer(struct spi_device *spi, struct spi_message *msg)
943a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
9449c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysinger	struct bfin_spi_master_data *drv_data = spi_master_get_devdata(spi->master);
945a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	unsigned long flags;
946a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
947a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	spin_lock_irqsave(&drv_data->lock, flags);
948a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
949f4f50c3ff7815d83dcbb19341f35db2f408ac4f8Mike Frysinger	if (!drv_data->running) {
950a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		spin_unlock_irqrestore(&drv_data->lock, flags);
951a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return -ESHUTDOWN;
952a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
953a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
954a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	msg->actual_length = 0;
955a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	msg->status = -EINPROGRESS;
956a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	msg->state = START_STATE;
957a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
95888b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu	dev_dbg(&spi->dev, "adding an msg in transfer() \n");
959a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	list_add_tail(&msg->queue, &drv_data->queue);
960a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
961f4f50c3ff7815d83dcbb19341f35db2f408ac4f8Mike Frysinger	if (drv_data->running && !drv_data->busy)
962a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		queue_work(drv_data->workqueue, &drv_data->pump_messages);
963a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
964a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	spin_unlock_irqrestore(&drv_data->lock, flags);
965a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
966a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	return 0;
967a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
968a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
96912e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang#define MAX_SPI_SSEL	7
97012e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang
971ddc0bf13d63715c2bce0fe8818fba12b82823283Mike Frysingerstatic const u16 ssel[][MAX_SPI_SSEL] = {
97212e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang	{P_SPI0_SSEL1, P_SPI0_SSEL2, P_SPI0_SSEL3,
97312e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang	P_SPI0_SSEL4, P_SPI0_SSEL5,
97412e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang	P_SPI0_SSEL6, P_SPI0_SSEL7},
97512e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang
97612e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang	{P_SPI1_SSEL1, P_SPI1_SSEL2, P_SPI1_SSEL3,
97712e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang	P_SPI1_SSEL4, P_SPI1_SSEL5,
97812e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang	P_SPI1_SSEL6, P_SPI1_SSEL7},
97912e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang
98012e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang	{P_SPI2_SSEL1, P_SPI2_SSEL2, P_SPI2_SSEL3,
98112e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang	P_SPI2_SSEL4, P_SPI2_SSEL5,
98212e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang	P_SPI2_SSEL6, P_SPI2_SSEL7},
98312e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang};
98412e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang
985ab09e0406ffd42d26fc9a6dcbb626f9eb1da9160Mike Frysinger/* setup for devices (may be called multiple times -- not just first setup) */
986138f97cd06deddd53ad496ac1656917a7b486d24Mike Frysingerstatic int bfin_spi_setup(struct spi_device *spi)
987a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
988ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack	struct bfin5xx_spi_chip *chip_info;
9899c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysinger	struct bfin_spi_slave_data *chip = NULL;
9909c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysinger	struct bfin_spi_master_data *drv_data = spi_master_get_devdata(spi->master);
9915b47bcd48b3bd53c86040321de0d348aadebed87Mike Frysinger	u16 bfin_ctl_reg;
992ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack	int ret = -EINVAL;
993a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
994a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Only alloc (or use chip_info) on first setup */
995ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack	chip_info = NULL;
996a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	chip = spi_get_ctldata(spi);
997a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (chip == NULL) {
998ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack		chip = kzalloc(sizeof(*chip), GFP_KERNEL);
999ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack		if (!chip) {
1000ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack			dev_err(&spi->dev, "cannot allocate chip data\n");
1001ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack			ret = -ENOMEM;
1002ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack			goto error;
1003ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack		}
1004a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1005a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		chip->enable_dma = 0;
1006a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		chip_info = spi->controller_data;
1007a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
1008a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
10095b47bcd48b3bd53c86040321de0d348aadebed87Mike Frysinger	/* Let people set non-standard bits directly */
10105b47bcd48b3bd53c86040321de0d348aadebed87Mike Frysinger	bfin_ctl_reg = BIT_CTL_OPENDRAIN | BIT_CTL_EMISO |
10115b47bcd48b3bd53c86040321de0d348aadebed87Mike Frysinger		BIT_CTL_PSSE | BIT_CTL_GM | BIT_CTL_SZ;
10125b47bcd48b3bd53c86040321de0d348aadebed87Mike Frysinger
1013a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* chip_info isn't always needed */
1014a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (chip_info) {
10152ed355165ff4ec834a75770f2a15dc87f5e06088Mike Frysinger		/* Make sure people stop trying to set fields via ctl_reg
10162ed355165ff4ec834a75770f2a15dc87f5e06088Mike Frysinger		 * when they should actually be using common SPI framework.
101790008a641dd832cc2e2c4d21b7da94de91e9d0a4Mike Frysinger		 * Currently we let through: WOM EMISO PSSE GM SZ.
10182ed355165ff4ec834a75770f2a15dc87f5e06088Mike Frysinger		 * Not sure if a user actually needs/uses any of these,
10192ed355165ff4ec834a75770f2a15dc87f5e06088Mike Frysinger		 * but let's assume (for now) they do.
10202ed355165ff4ec834a75770f2a15dc87f5e06088Mike Frysinger		 */
10215b47bcd48b3bd53c86040321de0d348aadebed87Mike Frysinger		if (chip_info->ctl_reg & ~bfin_ctl_reg) {
10222ed355165ff4ec834a75770f2a15dc87f5e06088Mike Frysinger			dev_err(&spi->dev, "do not set bits in ctl_reg "
10232ed355165ff4ec834a75770f2a15dc87f5e06088Mike Frysinger				"that the SPI framework manages\n");
1024ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack			goto error;
10252ed355165ff4ec834a75770f2a15dc87f5e06088Mike Frysinger		}
1026a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		chip->enable_dma = chip_info->enable_dma != 0
1027a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		    && drv_data->master_info->enable_dma;
1028a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		chip->ctl_reg = chip_info->ctl_reg;
1029a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		chip->cs_chg_udelay = chip_info->cs_chg_udelay;
103093b61bddc13d9acf1fe341b39d826e80f3182d1eWolfgang Muees		chip->idle_tx_val = chip_info->idle_tx_val;
1031f6a6d96685be6e784849d067b44acb831f595417Yi Li		chip->pio_interrupt = chip_info->pio_interrupt;
10325b47bcd48b3bd53c86040321de0d348aadebed87Mike Frysinger	} else {
10335b47bcd48b3bd53c86040321de0d348aadebed87Mike Frysinger		/* force a default base state */
10345b47bcd48b3bd53c86040321de0d348aadebed87Mike Frysinger		chip->ctl_reg &= bfin_ctl_reg;
1035033f44bd0ebca1809e8274237a64263d909f01a7Mike Frysinger	}
1036033f44bd0ebca1809e8274237a64263d909f01a7Mike Frysinger
10374d676fc5c39a677aa72148debd47029d8d8f0634Bob Liu	if (spi->bits_per_word % 8) {
1038033f44bd0ebca1809e8274237a64263d909f01a7Mike Frysinger		dev_err(&spi->dev, "%d bits_per_word is not supported\n",
1039033f44bd0ebca1809e8274237a64263d909f01a7Mike Frysinger				spi->bits_per_word);
1040033f44bd0ebca1809e8274237a64263d909f01a7Mike Frysinger		goto error;
1041a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
1042a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1043a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* translate common spi framework into our register */
10447715aad4ef5cccb318942a0c47aef8a39d6130d7Mike Frysinger	if (spi->mode & ~(SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST)) {
10457715aad4ef5cccb318942a0c47aef8a39d6130d7Mike Frysinger		dev_err(&spi->dev, "unsupported spi modes detected\n");
10467715aad4ef5cccb318942a0c47aef8a39d6130d7Mike Frysinger		goto error;
10477715aad4ef5cccb318942a0c47aef8a39d6130d7Mike Frysinger	}
1048a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (spi->mode & SPI_CPOL)
104990008a641dd832cc2e2c4d21b7da94de91e9d0a4Mike Frysinger		chip->ctl_reg |= BIT_CTL_CPOL;
1050a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (spi->mode & SPI_CPHA)
105190008a641dd832cc2e2c4d21b7da94de91e9d0a4Mike Frysinger		chip->ctl_reg |= BIT_CTL_CPHA;
1052a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (spi->mode & SPI_LSB_FIRST)
105390008a641dd832cc2e2c4d21b7da94de91e9d0a4Mike Frysinger		chip->ctl_reg |= BIT_CTL_LSBF;
1054a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* we dont support running in slave mode (yet?) */
105590008a641dd832cc2e2c4d21b7da94de91e9d0a4Mike Frysinger	chip->ctl_reg |= BIT_CTL_MASTER;
1056a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1057a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/*
1058a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	 * Notice: for blackfin, the speed_hz is the value of register
1059a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	 * SPI_BAUD, not the real baudrate
1060a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	 */
1061a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	chip->baud = hz_to_spi_baud(spi->max_speed_hz);
1062a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	chip->chip_select_num = spi->chip_select;
10634190f6a51f3f9c7c8298202d31b3ead9381c33f1Barry Song	if (chip->chip_select_num < MAX_CTRL_CS) {
10644190f6a51f3f9c7c8298202d31b3ead9381c33f1Barry Song		if (!(spi->mode & SPI_CPHA))
10654190f6a51f3f9c7c8298202d31b3ead9381c33f1Barry Song			dev_warn(&spi->dev, "Warning: SPI CPHA not set:"
10664190f6a51f3f9c7c8298202d31b3ead9381c33f1Barry Song				" Slave Select not under software control!\n"
10674190f6a51f3f9c7c8298202d31b3ead9381c33f1Barry Song				" See Documentation/blackfin/bfin-spi-notes.txt");
10684190f6a51f3f9c7c8298202d31b3ead9381c33f1Barry Song
1069d3cc71f71ae13596cb988e16bfa2b15f09fb7347Barry Song		chip->flag = (1 << spi->chip_select) << 8;
10704190f6a51f3f9c7c8298202d31b3ead9381c33f1Barry Song	} else
1071d3cc71f71ae13596cb988e16bfa2b15f09fb7347Barry Song		chip->cs_gpio = chip->chip_select_num - MAX_CTRL_CS;
1072a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1073f6a6d96685be6e784849d067b44acb831f595417Yi Li	if (chip->enable_dma && chip->pio_interrupt) {
1074f6a6d96685be6e784849d067b44acb831f595417Yi Li		dev_err(&spi->dev, "enable_dma is set, "
1075f6a6d96685be6e784849d067b44acb831f595417Yi Li				"do not set pio_interrupt\n");
1076f6a6d96685be6e784849d067b44acb831f595417Yi Li		goto error;
1077f6a6d96685be6e784849d067b44acb831f595417Yi Li	}
1078ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack	/*
1079ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack	 * if any one SPI chip is registered and wants DMA, request the
1080ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack	 * DMA channel for it
1081ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack	 */
1082ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack	if (chip->enable_dma && !drv_data->dma_requested) {
1083ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack		/* register dma irq handler */
1084ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack		ret = request_dma(drv_data->dma_channel, "BFIN_SPI_DMA");
1085ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack		if (ret) {
1086ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack			dev_err(&spi->dev,
1087ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack				"Unable to request BlackFin SPI DMA channel\n");
1088ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack			goto error;
1089ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack		}
1090ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack		drv_data->dma_requested = 1;
1091ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack
1092ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack		ret = set_dma_callback(drv_data->dma_channel,
1093ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack			bfin_spi_dma_irq_handler, drv_data);
1094ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack		if (ret) {
1095ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack			dev_err(&spi->dev, "Unable to set dma callback\n");
1096ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack			goto error;
1097ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack		}
1098ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack		dma_disable_irq(drv_data->dma_channel);
1099ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack	}
1100ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack
1101f6a6d96685be6e784849d067b44acb831f595417Yi Li	if (chip->pio_interrupt && !drv_data->irq_requested) {
1102f6a6d96685be6e784849d067b44acb831f595417Yi Li		ret = request_irq(drv_data->spi_irq, bfin_spi_pio_irq_handler,
110338ada214fad79ff5ebbed58932c5f0c9969d9c91Yong Zhang			0, "BFIN_SPI", drv_data);
1104f6a6d96685be6e784849d067b44acb831f595417Yi Li		if (ret) {
1105f6a6d96685be6e784849d067b44acb831f595417Yi Li			dev_err(&spi->dev, "Unable to register spi IRQ\n");
1106f6a6d96685be6e784849d067b44acb831f595417Yi Li			goto error;
1107f6a6d96685be6e784849d067b44acb831f595417Yi Li		}
1108f6a6d96685be6e784849d067b44acb831f595417Yi Li		drv_data->irq_requested = 1;
1109f6a6d96685be6e784849d067b44acb831f595417Yi Li		/* we use write mode, spi irq has to be disabled here */
1110f6a6d96685be6e784849d067b44acb831f595417Yi Li		disable_irq(drv_data->spi_irq);
1111f6a6d96685be6e784849d067b44acb831f595417Yi Li	}
1112f6a6d96685be6e784849d067b44acb831f595417Yi Li
1113d3cc71f71ae13596cb988e16bfa2b15f09fb7347Barry Song	if (chip->chip_select_num >= MAX_CTRL_CS) {
111473e1ac16258fe7e55cce4691e32c0b44d4579e08Michael Hennerich		/* Only request on first setup */
111573e1ac16258fe7e55cce4691e32c0b44d4579e08Michael Hennerich		if (spi_get_ctldata(spi) == NULL) {
111673e1ac16258fe7e55cce4691e32c0b44d4579e08Michael Hennerich			ret = gpio_request(chip->cs_gpio, spi->modalias);
111773e1ac16258fe7e55cce4691e32c0b44d4579e08Michael Hennerich			if (ret) {
111873e1ac16258fe7e55cce4691e32c0b44d4579e08Michael Hennerich				dev_err(&spi->dev, "gpio_request() error\n");
111973e1ac16258fe7e55cce4691e32c0b44d4579e08Michael Hennerich				goto pin_error;
112073e1ac16258fe7e55cce4691e32c0b44d4579e08Michael Hennerich			}
112173e1ac16258fe7e55cce4691e32c0b44d4579e08Michael Hennerich			gpio_direction_output(chip->cs_gpio, 1);
1122ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack		}
1123a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
1124a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1125898eb71cb17644964c5895fb190e79e3d0c49679Joe Perches	dev_dbg(&spi->dev, "setup spi chip %s, width is %d, dma is %d\n",
1126033f44bd0ebca1809e8274237a64263d909f01a7Mike Frysinger			spi->modalias, spi->bits_per_word, chip->enable_dma);
112788b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu	dev_dbg(&spi->dev, "ctl_reg is 0x%x, flag_reg is 0x%x\n",
1128a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan			chip->ctl_reg, chip->flag);
1129a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1130a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	spi_set_ctldata(spi, chip);
1131a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
113212e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang	dev_dbg(&spi->dev, "chip select number is %d\n", chip->chip_select_num);
1133d3cc71f71ae13596cb988e16bfa2b15f09fb7347Barry Song	if (chip->chip_select_num < MAX_CTRL_CS) {
1134ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack		ret = peripheral_request(ssel[spi->master->bus_num]
1135ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack		                         [chip->chip_select_num-1], spi->modalias);
1136ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack		if (ret) {
1137ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack			dev_err(&spi->dev, "peripheral_request() error\n");
1138ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack			goto pin_error;
1139ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack		}
1140ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack	}
114112e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang
11428221610e9990e7ee542a4e508d278302af8a9e75Barry Song	bfin_spi_cs_enable(drv_data, chip);
1143138f97cd06deddd53ad496ac1656917a7b486d24Mike Frysinger	bfin_spi_cs_deactive(drv_data, chip);
114407612e5f224613020c0ba17ce28e8eac052ef8ceSonic Zhang
1145a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	return 0;
1146ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack
1147ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack pin_error:
1148d3cc71f71ae13596cb988e16bfa2b15f09fb7347Barry Song	if (chip->chip_select_num >= MAX_CTRL_CS)
1149ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack		gpio_free(chip->cs_gpio);
1150ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack	else
1151ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack		peripheral_free(ssel[spi->master->bus_num]
1152ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack			[chip->chip_select_num - 1]);
1153ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack error:
1154ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack	if (chip) {
1155ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack		if (drv_data->dma_requested)
1156ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack			free_dma(drv_data->dma_channel);
1157ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack		drv_data->dma_requested = 0;
1158ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack
1159ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack		kfree(chip);
1160ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack		/* prevent free 'chip' twice */
1161ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack		spi_set_ctldata(spi, NULL);
1162ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack	}
1163ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack
1164ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack	return ret;
1165a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
1166a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1167a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan/*
1168a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan * callback for spi framework.
1169a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan * clean driver specific data
1170a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan */
1171138f97cd06deddd53ad496ac1656917a7b486d24Mike Frysingerstatic void bfin_spi_cleanup(struct spi_device *spi)
1172a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
11739c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysinger	struct bfin_spi_slave_data *chip = spi_get_ctldata(spi);
11749c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysinger	struct bfin_spi_master_data *drv_data = spi_master_get_devdata(spi->master);
1175a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1176e7d02e3c9577f070bc77354763bed7f24713dc53Mike Frysinger	if (!chip)
1177e7d02e3c9577f070bc77354763bed7f24713dc53Mike Frysinger		return;
1178e7d02e3c9577f070bc77354763bed7f24713dc53Mike Frysinger
1179d3cc71f71ae13596cb988e16bfa2b15f09fb7347Barry Song	if (chip->chip_select_num < MAX_CTRL_CS) {
118012e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang		peripheral_free(ssel[spi->master->bus_num]
118112e17c4267a5b2a5ba77bd53a62388be641534b8Sonic Zhang					[chip->chip_select_num-1]);
11828221610e9990e7ee542a4e508d278302af8a9e75Barry Song		bfin_spi_cs_disable(drv_data, chip);
1183d3cc71f71ae13596cb988e16bfa2b15f09fb7347Barry Song	} else
118442c78b2bf51bafb4cfa98dfecc28dd9b8bcd04b0Michael Hennerich		gpio_free(chip->cs_gpio);
118542c78b2bf51bafb4cfa98dfecc28dd9b8bcd04b0Michael Hennerich
1186a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	kfree(chip);
1187ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack	/* prevent free 'chip' twice */
1188ac01e97d644da8e947ffa1bde5083290fe2e36e7Daniel Mack	spi_set_ctldata(spi, NULL);
1189a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
1190a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1191c52d4e5f3cd3939bf44e788fdcbce8dcebb6fe61Mike Frysingerstatic int bfin_spi_init_queue(struct bfin_spi_master_data *drv_data)
1192a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
1193a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	INIT_LIST_HEAD(&drv_data->queue);
1194a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	spin_lock_init(&drv_data->lock);
1195a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1196f4f50c3ff7815d83dcbb19341f35db2f408ac4f8Mike Frysinger	drv_data->running = false;
1197a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->busy = 0;
1198a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1199a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* init transfer tasklet */
1200a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	tasklet_init(&drv_data->pump_transfers,
1201138f97cd06deddd53ad496ac1656917a7b486d24Mike Frysinger		     bfin_spi_pump_transfers, (unsigned long)drv_data);
1202a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1203a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* init messages workqueue */
1204138f97cd06deddd53ad496ac1656917a7b486d24Mike Frysinger	INIT_WORK(&drv_data->pump_messages, bfin_spi_pump_messages);
12056c7377ab6814c247d7600955a4ead2e3db490697Kay Sievers	drv_data->workqueue = create_singlethread_workqueue(
12066c7377ab6814c247d7600955a4ead2e3db490697Kay Sievers				dev_name(drv_data->master->dev.parent));
1207a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (drv_data->workqueue == NULL)
1208a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return -EBUSY;
1209a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1210a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	return 0;
1211a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
1212a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1213c52d4e5f3cd3939bf44e788fdcbce8dcebb6fe61Mike Frysingerstatic int bfin_spi_start_queue(struct bfin_spi_master_data *drv_data)
1214a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
1215a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	unsigned long flags;
1216a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1217a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	spin_lock_irqsave(&drv_data->lock, flags);
1218a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1219f4f50c3ff7815d83dcbb19341f35db2f408ac4f8Mike Frysinger	if (drv_data->running || drv_data->busy) {
1220a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		spin_unlock_irqrestore(&drv_data->lock, flags);
1221a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return -EBUSY;
1222a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
1223a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1224f4f50c3ff7815d83dcbb19341f35db2f408ac4f8Mike Frysinger	drv_data->running = true;
1225a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->cur_msg = NULL;
1226a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->cur_transfer = NULL;
1227a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->cur_chip = NULL;
1228a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	spin_unlock_irqrestore(&drv_data->lock, flags);
1229a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1230a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	queue_work(drv_data->workqueue, &drv_data->pump_messages);
1231a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1232a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	return 0;
1233a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
1234a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1235c52d4e5f3cd3939bf44e788fdcbce8dcebb6fe61Mike Frysingerstatic int bfin_spi_stop_queue(struct bfin_spi_master_data *drv_data)
1236a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
1237a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	unsigned long flags;
1238a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	unsigned limit = 500;
1239a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	int status = 0;
1240a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1241a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	spin_lock_irqsave(&drv_data->lock, flags);
1242a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1243a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/*
1244a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	 * This is a bit lame, but is optimized for the common execution path.
1245a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	 * A wait_queue on the drv_data->busy could be used, but then the common
1246a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	 * execution path (pump_messages) would be required to call wake_up or
1247a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	 * friends on every SPI message. Do this instead
1248a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	 */
1249f4f50c3ff7815d83dcbb19341f35db2f408ac4f8Mike Frysinger	drv_data->running = false;
1250850a28ecd8044ef36b2c7699d2e3736a410b4d0aVasily Khoruzhick	while ((!list_empty(&drv_data->queue) || drv_data->busy) && limit--) {
1251a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		spin_unlock_irqrestore(&drv_data->lock, flags);
1252a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		msleep(10);
1253a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		spin_lock_irqsave(&drv_data->lock, flags);
1254a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
1255a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1256a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (!list_empty(&drv_data->queue) || drv_data->busy)
1257a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		status = -EBUSY;
1258a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1259a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	spin_unlock_irqrestore(&drv_data->lock, flags);
1260a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1261a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	return status;
1262a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
1263a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1264c52d4e5f3cd3939bf44e788fdcbce8dcebb6fe61Mike Frysingerstatic int bfin_spi_destroy_queue(struct bfin_spi_master_data *drv_data)
1265a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
1266a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	int status;
1267a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1268138f97cd06deddd53ad496ac1656917a7b486d24Mike Frysinger	status = bfin_spi_stop_queue(drv_data);
1269a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (status != 0)
1270a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return status;
1271a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1272a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	destroy_workqueue(drv_data->workqueue);
1273a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1274a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	return 0;
1275a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
1276a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1277138f97cd06deddd53ad496ac1656917a7b486d24Mike Frysingerstatic int __init bfin_spi_probe(struct platform_device *pdev)
1278a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
1279a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct device *dev = &pdev->dev;
1280a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct bfin5xx_spi_master *platform_info;
1281a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	struct spi_master *master;
12829c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysinger	struct bfin_spi_master_data *drv_data;
1283a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu	struct resource *res;
1284a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	int status = 0;
1285a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1286a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	platform_info = dev->platform_data;
1287a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1288a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Allocate master with space for drv_data */
12892a045131db69c207b9e3f9614b2c9b0f2e82bcb7Mike Frysinger	master = spi_alloc_master(dev, sizeof(*drv_data));
1290a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (!master) {
1291a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		dev_err(&pdev->dev, "can not alloc spi_master\n");
1292a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return -ENOMEM;
1293a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
1294131b17d42de6194fa960132c1f62c29923c4f20cBryan Wu
1295a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data = spi_master_get_devdata(master);
1296a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->master = master;
1297a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->master_info = platform_info;
1298a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	drv_data->pdev = pdev;
1299003d922618150eaab53936f57ba8a61f2b601486Bryan Wu	drv_data->pin_req = platform_info->pin_req;
1300a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1301e7db06b5d5afcef15c4c3e61c3a7441ed7ad1407David Brownell	/* the spi->mode bits supported by this driver: */
1302e7db06b5d5afcef15c4c3e61c3a7441ed7ad1407David Brownell	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
1303e7db06b5d5afcef15c4c3e61c3a7441ed7ad1407David Brownell
1304a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	master->bus_num = pdev->id;
1305a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	master->num_chipselect = platform_info->num_chipselect;
1306138f97cd06deddd53ad496ac1656917a7b486d24Mike Frysinger	master->cleanup = bfin_spi_cleanup;
1307138f97cd06deddd53ad496ac1656917a7b486d24Mike Frysinger	master->setup = bfin_spi_setup;
1308138f97cd06deddd53ad496ac1656917a7b486d24Mike Frysinger	master->transfer = bfin_spi_transfer;
1309a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1310a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu	/* Find and map our resources */
1311a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1312a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu	if (res == NULL) {
1313a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu		dev_err(dev, "Cannot get IORESOURCE_MEM\n");
1314a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu		status = -ENOENT;
1315a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu		goto out_error_get_res;
1316a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu	}
1317a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu
131847885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger	drv_data->regs = ioremap(res->start, resource_size(res));
131947885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger	if (drv_data->regs == NULL) {
1320a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu		dev_err(dev, "Cannot map IO\n");
1321a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu		status = -ENXIO;
1322a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu		goto out_error_ioremap;
1323a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu	}
1324a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu
1325f6a6d96685be6e784849d067b44acb831f595417Yi Li	res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
1326f6a6d96685be6e784849d067b44acb831f595417Yi Li	if (res == NULL) {
1327a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu		dev_err(dev, "No DMA channel specified\n");
1328a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu		status = -ENOENT;
1329f6a6d96685be6e784849d067b44acb831f595417Yi Li		goto out_error_free_io;
1330f6a6d96685be6e784849d067b44acb831f595417Yi Li	}
1331f6a6d96685be6e784849d067b44acb831f595417Yi Li	drv_data->dma_channel = res->start;
1332f6a6d96685be6e784849d067b44acb831f595417Yi Li
1333f6a6d96685be6e784849d067b44acb831f595417Yi Li	drv_data->spi_irq = platform_get_irq(pdev, 0);
1334f6a6d96685be6e784849d067b44acb831f595417Yi Li	if (drv_data->spi_irq < 0) {
1335f6a6d96685be6e784849d067b44acb831f595417Yi Li		dev_err(dev, "No spi pio irq specified\n");
1336f6a6d96685be6e784849d067b44acb831f595417Yi Li		status = -ENOENT;
1337f6a6d96685be6e784849d067b44acb831f595417Yi Li		goto out_error_free_io;
1338a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu	}
1339a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu
1340a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Initial and start queue */
1341138f97cd06deddd53ad496ac1656917a7b486d24Mike Frysinger	status = bfin_spi_init_queue(drv_data);
1342a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (status != 0) {
1343a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu		dev_err(dev, "problem initializing queue\n");
1344a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		goto out_error_queue_alloc;
1345a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
1346a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu
1347138f97cd06deddd53ad496ac1656917a7b486d24Mike Frysinger	status = bfin_spi_start_queue(drv_data);
1348a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (status != 0) {
1349a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu		dev_err(dev, "problem starting queue\n");
1350a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		goto out_error_queue_alloc;
1351a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
1352a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1353f9e522caece074b9a985436d611127e8e96ad446Vitja Makarov	status = peripheral_request_list(drv_data->pin_req, DRV_NAME);
1354f9e522caece074b9a985436d611127e8e96ad446Vitja Makarov	if (status != 0) {
1355f9e522caece074b9a985436d611127e8e96ad446Vitja Makarov		dev_err(&pdev->dev, ": Requesting Peripherals failed\n");
1356f9e522caece074b9a985436d611127e8e96ad446Vitja Makarov		goto out_error_queue_alloc;
1357f9e522caece074b9a985436d611127e8e96ad446Vitja Makarov	}
1358f9e522caece074b9a985436d611127e8e96ad446Vitja Makarov
1359bb8beecd98de45f821a3360e0b061fc1f8da947cWolfgang Muees	/* Reset SPI registers. If these registers were used by the boot loader,
1360bb8beecd98de45f821a3360e0b061fc1f8da947cWolfgang Muees	 * the sky may fall on your head if you enable the dma controller.
1361bb8beecd98de45f821a3360e0b061fc1f8da947cWolfgang Muees	 */
136247885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger	bfin_write(&drv_data->regs->ctl, BIT_CTL_CPHA | BIT_CTL_MASTER);
136347885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger	bfin_write(&drv_data->regs->flg, 0xFF00);
1364bb8beecd98de45f821a3360e0b061fc1f8da947cWolfgang Muees
1365a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Register with the SPI framework */
1366a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	platform_set_drvdata(pdev, drv_data);
1367a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	status = spi_register_master(master);
1368a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (status != 0) {
1369a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu		dev_err(dev, "problem registering spi master\n");
1370a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		goto out_error_queue_alloc;
1371a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
1372a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu
137347885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger	dev_info(dev, "%s, Version %s, regs@%p, dma channel@%d\n",
137447885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger		DRV_DESC, DRV_VERSION, drv_data->regs,
1375bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		drv_data->dma_channel);
1376a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	return status;
1377a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1378cc2f81a695640dd1c0cf12b35ee303460fa6d0bcMichael Hennerichout_error_queue_alloc:
1379138f97cd06deddd53ad496ac1656917a7b486d24Mike Frysinger	bfin_spi_destroy_queue(drv_data);
1380f6a6d96685be6e784849d067b44acb831f595417Yi Liout_error_free_io:
138147885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger	iounmap(drv_data->regs);
1382a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wuout_error_ioremap:
1383a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wuout_error_get_res:
1384a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	spi_master_put(master);
1385cc2f81a695640dd1c0cf12b35ee303460fa6d0bcMichael Hennerich
1386a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	return status;
1387a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
1388a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1389a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan/* stop hardware and remove the driver */
1390138f97cd06deddd53ad496ac1656917a7b486d24Mike Frysingerstatic int __devexit bfin_spi_remove(struct platform_device *pdev)
1391a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
13929c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysinger	struct bfin_spi_master_data *drv_data = platform_get_drvdata(pdev);
1393a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	int status = 0;
1394a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1395a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (!drv_data)
1396a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return 0;
1397a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1398a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Remove the queue */
1399138f97cd06deddd53ad496ac1656917a7b486d24Mike Frysinger	status = bfin_spi_destroy_queue(drv_data);
1400a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (status != 0)
1401a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return status;
1402a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1403a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Disable the SSP at the peripheral and SOC level */
1404a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	bfin_spi_disable(drv_data);
1405a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1406a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Release DMA */
1407a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (drv_data->master_info->enable_dma) {
1408bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu		if (dma_channel_active(drv_data->dma_channel))
1409bb90eb00b6c28c8be5a69c6b58d5a6924f6f2ad7Bryan Wu			free_dma(drv_data->dma_channel);
1410a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
1411a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1412f6a6d96685be6e784849d067b44acb831f595417Yi Li	if (drv_data->irq_requested) {
1413f6a6d96685be6e784849d067b44acb831f595417Yi Li		free_irq(drv_data->spi_irq, drv_data);
1414f6a6d96685be6e784849d067b44acb831f595417Yi Li		drv_data->irq_requested = 0;
1415f6a6d96685be6e784849d067b44acb831f595417Yi Li	}
1416f6a6d96685be6e784849d067b44acb831f595417Yi Li
1417a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Disconnect from the SPI framework */
1418a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	spi_unregister_master(drv_data->master);
1419a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1420003d922618150eaab53936f57ba8a61f2b601486Bryan Wu	peripheral_free_list(drv_data->pin_req);
1421cc2f81a695640dd1c0cf12b35ee303460fa6d0bcMichael Hennerich
1422a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Prevent double remove */
1423a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	platform_set_drvdata(pdev, NULL);
1424a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1425a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	return 0;
1426a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
1427a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1428a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#ifdef CONFIG_PM
1429138f97cd06deddd53ad496ac1656917a7b486d24Mike Frysingerstatic int bfin_spi_suspend(struct platform_device *pdev, pm_message_t state)
1430a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
14319c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysinger	struct bfin_spi_master_data *drv_data = platform_get_drvdata(pdev);
1432a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	int status = 0;
1433a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1434138f97cd06deddd53ad496ac1656917a7b486d24Mike Frysinger	status = bfin_spi_stop_queue(drv_data);
1435a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (status != 0)
1436a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return status;
1437a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
143847885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger	drv_data->ctrl_reg = bfin_read(&drv_data->regs->ctl);
143947885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger	drv_data->flag_reg = bfin_read(&drv_data->regs->flg);
1440b052fd0a44354c655eb98fd715ef52857631dfefBarry Song
1441b052fd0a44354c655eb98fd715ef52857631dfefBarry Song	/*
1442b052fd0a44354c655eb98fd715ef52857631dfefBarry Song	 * reset SPI_CTL and SPI_FLG registers
1443b052fd0a44354c655eb98fd715ef52857631dfefBarry Song	 */
144447885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger	bfin_write(&drv_data->regs->ctl, BIT_CTL_CPHA | BIT_CTL_MASTER);
144547885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger	bfin_write(&drv_data->regs->flg, 0xFF00);
1446a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1447a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	return 0;
1448a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
1449a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1450138f97cd06deddd53ad496ac1656917a7b486d24Mike Frysingerstatic int bfin_spi_resume(struct platform_device *pdev)
1451a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
14529c0a788b4315b83f6138ffa15c56ccf541106e58Mike Frysinger	struct bfin_spi_master_data *drv_data = platform_get_drvdata(pdev);
1453a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	int status = 0;
1454a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
145547885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger	bfin_write(&drv_data->regs->ctl, drv_data->ctrl_reg);
145647885ce81c7498c015e6763303821ab6e8a6e2ccMike Frysinger	bfin_write(&drv_data->regs->flg, drv_data->flag_reg);
1457a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1458a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	/* Start the queue running */
1459138f97cd06deddd53ad496ac1656917a7b486d24Mike Frysinger	status = bfin_spi_start_queue(drv_data);
1460a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	if (status != 0) {
1461a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		dev_err(&pdev->dev, "problem starting queue (%d)\n", status);
1462a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan		return status;
1463a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	}
1464a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1465a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan	return 0;
1466a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
1467a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#else
1468138f97cd06deddd53ad496ac1656917a7b486d24Mike Frysinger#define bfin_spi_suspend NULL
1469138f97cd06deddd53ad496ac1656917a7b486d24Mike Frysinger#define bfin_spi_resume NULL
1470a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan#endif				/* CONFIG_PM */
1471a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
14727e38c3c4453bdb5ffdf8bf0ff0d9a760540f0893Kay SieversMODULE_ALIAS("platform:bfin-spi");
1473138f97cd06deddd53ad496ac1656917a7b486d24Mike Frysingerstatic struct platform_driver bfin_spi_driver = {
1474fc3ba9525b50ea0d1670357ece21ebedcee507aeDavid Brownell	.driver	= {
1475a32c691d7cf5c37af753255ef4843b18a31935b9Bryan Wu		.name	= DRV_NAME,
147688b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu		.owner	= THIS_MODULE,
147788b4036934b5a6d8cda810487503d2fc4c46d448Bryan Wu	},
1478138f97cd06deddd53ad496ac1656917a7b486d24Mike Frysinger	.suspend	= bfin_spi_suspend,
1479138f97cd06deddd53ad496ac1656917a7b486d24Mike Frysinger	.resume		= bfin_spi_resume,
1480138f97cd06deddd53ad496ac1656917a7b486d24Mike Frysinger	.remove		= __devexit_p(bfin_spi_remove),
1481a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan};
1482a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1483138f97cd06deddd53ad496ac1656917a7b486d24Mike Frysingerstatic int __init bfin_spi_init(void)
1484a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
1485138f97cd06deddd53ad496ac1656917a7b486d24Mike Frysinger	return platform_driver_probe(&bfin_spi_driver, bfin_spi_probe);
1486a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
14876f7c17f4f91513247dfec52d6968cd70d5251b38Michael Hennerichsubsys_initcall(bfin_spi_init);
1488a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan
1489138f97cd06deddd53ad496ac1656917a7b486d24Mike Frysingerstatic void __exit bfin_spi_exit(void)
1490a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan{
1491138f97cd06deddd53ad496ac1656917a7b486d24Mike Frysinger	platform_driver_unregister(&bfin_spi_driver);
1492a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77Wu, Bryan}
1493138f97cd06deddd53ad496ac1656917a7b486d24Mike Frysingermodule_exit(bfin_spi_exit);
1494