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