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