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