--- /dev/null
+/*drivers/serial/rk29xx_spim.c - driver for rk29xx spim device \r
+ *\r
+ * Copyright (C) 2010 ROCKCHIP, Inc.\r
+ *\r
+ * This software is licensed under the terms of the GNU General Public\r
+ * License version 2, as published by the Free Software Foundation, and\r
+ * may be copied, distributed, and modified under those terms.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU General Public License for more details.\r
+ */\r
+\r
+#include <linux/dma-mapping.h>\r
+#include <linux/interrupt.h>\r
+#include <linux/highmem.h>\r
+#include <linux/delay.h>\r
+#include <linux/slab.h>\r
+#include <linux/platform_device.h>\r
+#include <linux/clk.h>\r
+#include <linux/cpufreq.h>\r
+#include <mach/gpio.h>\r
+#include <linux/dma-mapping.h>\r
+#include <asm/dma.h>\r
+\r
+#include "rk29xx_spim.h"\r
+#include <linux/spi/spi.h>\r
+#include <mach/board.h>\r
+\r
+#ifdef CONFIG_DEBUG_FS\r
+#include <linux/debugfs.h>\r
+#endif\r
+\r
+/*ÔÓеÄspiÇý¶¯Ð§ÂʱȽϵͣ¬\r
+ÎÞ·¨Âú×ã´óÊý¾ÝÁ¿µÄ´«Ê䣻\r
+QUICK_TRANSFERÓÃÓÚ¿ìËÙ´«Ê䣬ͬʱ¿ÉÖ¸¶¨°ëË«¹¤»òÈ«Ë«¹¤£¬\r
+ĬÈÏʹÓðëË«¹¤\r
+*/\r
+\r
+#define QUICK_TRANSFER \r
+\r
+#if 1\r
+#define DBG(x...) printk(x)\r
+#else\r
+#define DBG(x...)\r
+#endif\r
+\r
+#define DMA_MIN_BYTES 8\r
+\r
+\r
+#define START_STATE ((void *)0)\r
+#define RUNNING_STATE ((void *)1)\r
+#define DONE_STATE ((void *)2)\r
+#define ERROR_STATE ((void *)-1)\r
+\r
+#define QUEUE_RUNNING 0\r
+#define QUEUE_STOPPED 1\r
+\r
+#define MRST_SPI_DEASSERT 0\r
+#define MRST_SPI_ASSERT 1 ///CS0\r
+#define MRST_SPI_ASSERT1 2 ///CS1\r
+\r
+/* Slave spi_dev related */\r
+struct chip_data {\r
+ u16 cr0;\r
+ u8 cs; /* chip select pin */\r
+ u8 n_bytes; /* current is a 1/2/4 byte op */\r
+ u8 tmode; /* TR/TO/RO/EEPROM */\r
+ u8 type; /* SPI/SSP/MicroWire */\r
+\r
+ u8 poll_mode; /* 1 means use poll mode */\r
+\r
+ u32 dma_width;\r
+ u32 rx_threshold;\r
+ u32 tx_threshold;\r
+ u8 enable_dma:1;\r
+ u8 bits_per_word;\r
+ u16 clk_div; /* baud rate divider */\r
+ u32 speed_hz; /* baud rate */\r
+ int (*write)(struct rk29xx_spi *dws);\r
+ int (*read)(struct rk29xx_spi *dws);\r
+ void (*cs_control)(struct rk29xx_spi *dws, u32 cs, u8 flag);\r
+};\r
+\r
+#define SUSPND (1<<0)\r
+#define SPIBUSY (1<<1)\r
+#define RXBUSY (1<<2)\r
+#define TXBUSY (1<<3)\r
+\r
+#ifdef CONFIG_DEBUG_FS\r
+static int spi_show_regs_open(struct inode *inode, struct file *file)\r
+{\r
+ file->private_data = inode->i_private;\r
+ return 0;\r
+}\r
+\r
+#define SPI_REGS_BUFSIZE 1024\r
+static ssize_t spi_show_regs(struct file *file, char __user *user_buf,\r
+ size_t count, loff_t *ppos)\r
+{\r
+ struct rk29xx_spi *dws;\r
+ char *buf;\r
+ u32 len = 0;\r
+ ssize_t ret;\r
+\r
+ dws = file->private_data;\r
+\r
+ buf = kzalloc(SPI_REGS_BUFSIZE, GFP_KERNEL);\r
+ if (!buf)\r
+ return 0;\r
+\r
+ len += printk(buf + len, SPI_REGS_BUFSIZE - len,\r
+ "MRST SPI0 registers:\n");\r
+ len += printk(buf + len, SPI_REGS_BUFSIZE - len,\r
+ "=================================\n");\r
+ len += printk(buf + len, SPI_REGS_BUFSIZE - len,\r
+ "CTRL0: \t\t0x%08x\n", rk29xx_readl(dws, SPIM_CTRLR0));\r
+ len += printk(buf + len, SPI_REGS_BUFSIZE - len,\r
+ "CTRL1: \t\t0x%08x\n", rk29xx_readl(dws, SPIM_CTRLR1));\r
+ len += printk(buf + len, SPI_REGS_BUFSIZE - len,\r
+ "SSIENR: \t0x%08x\n", rk29xx_readl(dws, SPIM_ENR));\r
+ len += printk(buf + len, SPI_REGS_BUFSIZE - len,\r
+ "SER: \t\t0x%08x\n", rk29xx_readl(dws, SPIM_SER));\r
+ len += printk(buf + len, SPI_REGS_BUFSIZE - len,\r
+ "BAUDR: \t\t0x%08x\n", rk29xx_readl(dws, SPIM_BAUDR));\r
+ len += printk(buf + len, SPI_REGS_BUFSIZE - len,\r
+ "TXFTLR: \t0x%08x\n", rk29xx_readl(dws, SPIM_TXFTLR));\r
+ len += printk(buf + len, SPI_REGS_BUFSIZE - len,\r
+ "RXFTLR: \t0x%08x\n", rk29xx_readl(dws, SPIM_RXFTLR));\r
+ len += printk(buf + len, SPI_REGS_BUFSIZE - len,\r
+ "TXFLR: \t\t0x%08x\n", rk29xx_readl(dws, SPIM_TXFLR));\r
+ len += printk(buf + len, SPI_REGS_BUFSIZE - len,\r
+ "RXFLR: \t\t0x%08x\n", rk29xx_readl(dws, SPIM_RXFLR));\r
+ len += printk(buf + len, SPI_REGS_BUFSIZE - len,\r
+ "SR: \t\t0x%08x\n", rk29xx_readl(dws, SPIM_SR));\r
+ len += printk(buf + len, SPI_REGS_BUFSIZE - len,\r
+ "IMR: \t\t0x%08x\n", rk29xx_readl(dws, SPIM_IMR));\r
+ len += printk(buf + len, SPI_REGS_BUFSIZE - len,\r
+ "ISR: \t\t0x%08x\n", rk29xx_readl(dws, SPIM_ISR));\r
+ len += printk(buf + len, SPI_REGS_BUFSIZE - len,\r
+ "DMACR: \t\t0x%08x\n", rk29xx_readl(dws, SPIM_DMACR));\r
+ len += printk(buf + len, SPI_REGS_BUFSIZE - len,\r
+ "DMATDLR: \t0x%08x\n", rk29xx_readl(dws, SPIM_DMATDLR));\r
+ len += printk(buf + len, SPI_REGS_BUFSIZE - len,\r
+ "DMARDLR: \t0x%08x\n", rk29xx_readl(dws, SPIM_DMARDLR));\r
+ len += printk(buf + len, SPI_REGS_BUFSIZE - len,\r
+ "=================================\n");\r
+\r
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);\r
+ kfree(buf);\r
+ return ret;\r
+}\r
+\r
+static const struct file_operations mrst_spi_regs_ops = {\r
+ .owner = THIS_MODULE,\r
+ .open = spi_show_regs_open,\r
+ .read = spi_show_regs,\r
+};\r
+\r
+static int mrst_spi_debugfs_init(struct rk29xx_spi *dws)\r
+{\r
+ dws->debugfs = debugfs_create_dir("mrst_spi", NULL);\r
+ if (!dws->debugfs)\r
+ return -ENOMEM;\r
+\r
+ debugfs_create_file("registers", S_IFREG | S_IRUGO,\r
+ dws->debugfs, (void *)dws, &mrst_spi_regs_ops);\r
+ return 0;\r
+}\r
+\r
+static void mrst_spi_debugfs_remove(struct rk29xx_spi *dws)\r
+{\r
+ if (dws->debugfs)\r
+ debugfs_remove_recursive(dws->debugfs);\r
+}\r
+\r
+#else\r
+static inline int mrst_spi_debugfs_init(struct rk29xx_spi *dws)\r
+{\r
+ return 0;\r
+}\r
+\r
+static inline void mrst_spi_debugfs_remove(struct rk29xx_spi *dws)\r
+{\r
+}\r
+#endif /* CONFIG_DEBUG_FS */\r
+\r
+static void wait_till_not_busy(struct rk29xx_spi *dws)\r
+{\r
+ unsigned long end = jiffies + 1 + usecs_to_jiffies(1000);\r
+\r
+ while (time_before(jiffies, end)) {\r
+ if (!(rk29xx_readw(dws, SPIM_SR) & SR_BUSY))\r
+ return;\r
+ }\r
+ dev_err(&dws->master->dev,\r
+ "DW SPI: Status keeps busy for 1000us after a read/write!\n");\r
+}\r
+\r
+static void wait_till_tf_empty(struct rk29xx_spi *dws)\r
+{\r
+ unsigned long end = jiffies + 1 + usecs_to_jiffies(1000);\r
+\r
+ while (time_before(jiffies, end)) {\r
+ if (rk29xx_readw(dws, SPIM_SR) & SR_TF_EMPT)\r
+ return;\r
+ }\r
+ dev_err(&dws->master->dev,\r
+ "DW SPI: Status keeps busy for 1000us after a read/write!\n");\r
+}\r
+\r
+static void flush(struct rk29xx_spi *dws)\r
+{\r
+ while (!(rk29xx_readw(dws, SPIM_SR) & SR_RF_EMPT))\r
+ rk29xx_readw(dws, SPIM_RXDR);\r
+\r
+ wait_till_not_busy(dws);\r
+}\r
+\r
+static void spi_cs_control(struct rk29xx_spi *dws, u32 cs, u8 flag)\r
+{\r
+ struct rk29xx_spi_platform_data *pdata = dws->master->dev.platform_data;\r
+ struct spi_cs_gpio *cs_gpios = pdata->chipselect_gpios;\r
+\r
+ if (flag == 0)\r
+ gpio_direction_output(cs_gpios[cs].cs_gpio, GPIO_HIGH);\r
+ else\r
+ gpio_direction_output(cs_gpios[cs].cs_gpio, GPIO_LOW);\r
+}\r
+\r
+static int null_writer(struct rk29xx_spi *dws)\r
+{\r
+ u8 n_bytes = dws->n_bytes;\r
+\r
+ if ((rk29xx_readw(dws, SPIM_SR) & SR_TF_FULL)\r
+ || (dws->tx == dws->tx_end))\r
+ return 0;\r
+ rk29xx_writew(dws, SPIM_TXDR, 0);\r
+ dws->tx += n_bytes;\r
+ //wait_till_not_busy(dws);\r
+\r
+ return 1;\r
+}\r
+\r
+static int null_reader(struct rk29xx_spi *dws)\r
+{\r
+ u8 n_bytes = dws->n_bytes;\r
+ while ((!(rk29xx_readw(dws, SPIM_SR) & SR_RF_EMPT))\r
+ && (dws->rx < dws->rx_end)) {\r
+ rk29xx_readw(dws, SPIM_RXDR);\r
+ dws->rx += n_bytes;\r
+ }\r
+ wait_till_not_busy(dws);\r
+ return dws->rx == dws->rx_end;\r
+}\r
+\r
+static int u8_writer(struct rk29xx_spi *dws)\r
+{ \r
+ if ((rk29xx_readw(dws, SPIM_SR) & SR_TF_FULL)\r
+ || (dws->tx == dws->tx_end))\r
+ return 0;\r
+ DBG(KERN_INFO "ctrl0: 0x%x\n", rk29xx_readl(dws, SPIM_CTRLR0));\r
+ rk29xx_writew(dws, SPIM_TXDR, *(u8 *)(dws->tx));\r
+ DBG(KERN_INFO "dws->tx:%x\n", *(u8 *)(dws->tx));\r
+ ++dws->tx;\r
+ //wait_till_not_busy(dws);\r
+\r
+ return 1;\r
+}\r
+\r
+static int u8_reader(struct rk29xx_spi *dws)\r
+{\r
+ while (!(rk29xx_readw(dws, SPIM_SR) & SR_RF_EMPT)\r
+ && (dws->rx < dws->rx_end)) {\r
+ printk(KERN_INFO "ctrl0: 0x%x\n", rk29xx_readl(dws, SPIM_CTRLR0));\r
+ *(u8 *)(dws->rx) = rk29xx_readw(dws, SPIM_RXDR) & 0xFFU;\r
+ printk(KERN_INFO "dws->rx:%x\n", *(u8 *)(dws->rx));\r
+ ++dws->rx;\r
+ }\r
+\r
+ wait_till_not_busy(dws);\r
+ return dws->rx == dws->rx_end;\r
+}\r
+\r
+static int u16_writer(struct rk29xx_spi *dws)\r
+{\r
+ if ((rk29xx_readw(dws, SPIM_SR) & SR_TF_FULL)\r
+ || (dws->tx == dws->tx_end))\r
+ return 0;\r
+\r
+ rk29xx_writew(dws, SPIM_TXDR, *(u16 *)(dws->tx));\r
+ dws->tx += 2;\r
+ //wait_till_not_busy(dws);\r
+\r
+ return 1;\r
+}\r
+\r
+static int u16_reader(struct rk29xx_spi *dws)\r
+{\r
+ u16 temp;\r
+\r
+ while (!(rk29xx_readw(dws, SPIM_SR) & SR_RF_EMPT)\r
+ && (dws->rx < dws->rx_end)) {\r
+ temp = rk29xx_readw(dws, SPIM_RXDR);\r
+ printk(KERN_INFO "dws->rx:%02x\n", temp);\r
+ *(u16 *)(dws->rx) = temp;\r
+ dws->rx += 2;\r
+ }\r
+\r
+ wait_till_not_busy(dws);\r
+ return dws->rx == dws->rx_end;\r
+}\r
+\r
+static void *next_transfer(struct rk29xx_spi *dws)\r
+{\r
+ struct spi_message *msg = dws->cur_msg;\r
+ struct spi_transfer *trans = dws->cur_transfer;\r
+\r
+ /* Move to next transfer */\r
+ if (trans->transfer_list.next != &msg->transfers) {\r
+ dws->cur_transfer =\r
+ list_entry(trans->transfer_list.next,\r
+ struct spi_transfer,\r
+ transfer_list);\r
+ return RUNNING_STATE;\r
+ } else\r
+ return DONE_STATE;\r
+}\r
+\r
+static void rk29_spi_dma_rxcb(struct rk29_dma_chan *chan, void *buf_id,\r
+ int size, enum rk29_dma_buffresult res)\r
+{\r
+ struct rk29xx_spi *dws = buf_id;\r
+ unsigned long flags;\r
+\r
+ spin_lock_irqsave(&dws->lock, flags);\r
+\r
+ if (res == RK29_RES_OK)\r
+ dws->state &= ~RXBUSY;\r
+ else\r
+ dev_err(&dws->master->dev, "DmaAbrtRx-%d\n", size);\r
+\r
+ /* If the other done */\r
+ if (!(dws->state & TXBUSY))\r
+ complete(&dws->xfer_completion);\r
+\r
+ spin_unlock_irqrestore(&dws->lock, flags);\r
+}\r
+\r
+static void rk29_spi_dma_txcb(struct rk29_dma_chan *chan, void *buf_id,\r
+ int size, enum rk29_dma_buffresult res)\r
+{\r
+ struct rk29xx_spi *dws = buf_id;\r
+ unsigned long flags;\r
+\r
+ spin_lock_irqsave(&dws->lock, flags);\r
+\r
+ if (res == RK29_RES_OK)\r
+ dws->state &= ~TXBUSY;\r
+ else\r
+ dev_err(&dws->master->dev, "DmaAbrtTx-%d \n", size);\r
+\r
+ /* If the other done */\r
+ if (!(dws->state & RXBUSY))\r
+ complete(&dws->xfer_completion);\r
+\r
+ spin_unlock_irqrestore(&dws->lock, flags);\r
+}\r
+\r
+\r
+static struct rk29_dma_client rk29_spi_dma_client = {\r
+ .name = "rk29xx-spi-dma",\r
+};\r
+\r
+static int acquire_dma(struct rk29xx_spi *dws)\r
+{\r
+ #if 1\r
+ dws->dma_inited = 0;\r
+ return 1;\r
+ #endif\r
+ \r
+ if (dws->dma_inited) {\r
+ return 1;\r
+ }\r
+\r
+ printk(KERN_INFO "request dma\n");\r
+ if(rk29_dma_request(dws->rx_dmach, \r
+ &rk29_spi_dma_client, NULL) < 0) {\r
+ dev_err(&dws->master->dev, "dws->rx_dmach : %d, cannot get RxDMA\n", dws->rx_dmach);\r
+ return 0;\r
+ }\r
+ DBG(KERN_INFO "request dma success\n");\r
+\r
+ rk29_dma_set_buffdone_fn(dws->rx_dmach, rk29_spi_dma_rxcb);\r
+ rk29_dma_devconfig(dws->rx_dmach, RK29_DMASRC_HW,\r
+ dws->sfr_start + SPIM_RXDR);\r
+\r
+ if (rk29_dma_request(dws->tx_dmach,\r
+ &rk29_spi_dma_client, NULL) < 0) {\r
+ dev_err(&dws->master->dev, "dws->tx_dmach : %d, cannot get TxDMA\n", dws->tx_dmach);\r
+ rk29_dma_free(dws->rx_dmach, &rk29_spi_dma_client);\r
+ return 0;\r
+ }\r
+ rk29_dma_set_buffdone_fn(dws->tx_dmach, rk29_spi_dma_txcb);\r
+ rk29_dma_devconfig(dws->tx_dmach, RK29_DMASRC_MEM,\r
+ dws->sfr_start + SPIM_TXDR);\r
+\r
+ dws->dma_inited = 1;\r
+ return 1;\r
+}\r
+\r
+/*\r
+ * Note: first step is the protocol driver prepares\r
+ * a dma-capable memory, and this func just need translate\r
+ * the virt addr to physical\r
+ */\r
+static int map_dma_buffers(struct rk29xx_spi *dws)\r
+{ \r
+ if (!dws->cur_msg->is_dma_mapped || !dws->dma_inited\r
+ || !dws->cur_chip->enable_dma)\r
+ return 0;\r
+\r
+ if (dws->cur_transfer->tx_dma)\r
+ dws->tx_dma = dws->cur_transfer->tx_dma;\r
+\r
+ if (dws->cur_transfer->rx_dma)\r
+ dws->rx_dma = dws->cur_transfer->rx_dma;\r
+\r
+ return 1;\r
+}\r
+\r
+/* Caller already set message->status; dma and pio irqs are blocked */\r
+static void giveback(struct rk29xx_spi *dws)\r
+{\r
+ struct spi_transfer *last_transfer;\r
+ unsigned long flags;\r
+ struct spi_message *msg;\r
+\r
+ spin_lock_irqsave(&dws->lock, flags);\r
+ msg = dws->cur_msg;\r
+ dws->cur_msg = NULL;\r
+ dws->cur_transfer = NULL;\r
+ dws->prev_chip = dws->cur_chip;\r
+ dws->cur_chip = NULL;\r
+ dws->dma_mapped = 0;\r
+ queue_work(dws->workqueue, &dws->pump_messages);\r
+ spin_unlock_irqrestore(&dws->lock, flags);\r
+\r
+ last_transfer = list_entry(msg->transfers.prev,\r
+ struct spi_transfer,\r
+ transfer_list);\r
+\r
+ if (!last_transfer->cs_change)\r
+ dws->cs_control(dws,msg->spi->chip_select,MRST_SPI_DEASSERT);\r
+\r
+ msg->state = NULL;\r
+ if (msg->complete)\r
+ msg->complete(msg->context);\r
+}\r
+\r
+static void int_error_stop(struct rk29xx_spi *dws, const char *msg)\r
+{\r
+ /* Stop and reset hw */\r
+ flush(dws);\r
+ spi_enable_chip(dws, 0);\r
+\r
+ dev_err(&dws->master->dev, "%s\n", msg);\r
+ dws->cur_msg->state = ERROR_STATE;\r
+ tasklet_schedule(&dws->pump_transfers);\r
+}\r
+\r
+static void transfer_complete(struct rk29xx_spi *dws)\r
+{\r
+ /* Update total byte transfered return count actual bytes read */\r
+ dws->cur_msg->actual_length += dws->len;\r
+\r
+ /* Move to next transfer */\r
+ dws->cur_msg->state = next_transfer(dws);\r
+\r
+ /* Handle end of message */\r
+ if (dws->cur_msg->state == DONE_STATE) {\r
+ dws->cur_msg->status = 0;\r
+ giveback(dws);\r
+ } else\r
+ tasklet_schedule(&dws->pump_transfers);\r
+}\r
+\r
+static irqreturn_t interrupt_transfer(struct rk29xx_spi *dws)\r
+{\r
+ u16 irq_status, irq_mask = 0x3f;\r
+ u32 int_level = dws->fifo_len / 2;\r
+ u32 left;\r
+ \r
+ irq_status = rk29xx_readw(dws, SPIM_ISR) & irq_mask;\r
+ /* Error handling */\r
+ if (irq_status & (SPI_INT_TXOI | SPI_INT_RXOI | SPI_INT_RXUI)) {\r
+ rk29xx_writew(dws, SPIM_ICR, SPI_CLEAR_INT_TXOI | SPI_CLEAR_INT_RXOI | SPI_CLEAR_INT_RXUI);\r
+ int_error_stop(dws, "interrupt_transfer: fifo overrun");\r
+ return IRQ_HANDLED;\r
+ }\r
+\r
+ if (irq_status & SPI_INT_TXEI) {\r
+ spi_mask_intr(dws, SPI_INT_TXEI);\r
+\r
+ left = (dws->tx_end - dws->tx) / dws->n_bytes;\r
+ left = (left > int_level) ? int_level : left;\r
+\r
+ while (left--) {\r
+ dws->write(dws);\r
+ wait_till_not_busy(dws);\r
+ }\r
+ dws->read(dws);\r
+\r
+ /* Re-enable the IRQ if there is still data left to tx */\r
+ if (dws->tx_end > dws->tx)\r
+ spi_umask_intr(dws, SPI_INT_TXEI);\r
+ else\r
+ transfer_complete(dws);\r
+ }\r
+\r
+ return IRQ_HANDLED;\r
+}\r
+\r
+static irqreturn_t rk29xx_spi_irq(int irq, void *dev_id)\r
+{\r
+ struct rk29xx_spi *dws = dev_id;\r
+\r
+ if (!dws->cur_msg) {\r
+ spi_mask_intr(dws, SPI_INT_TXEI);\r
+ /* Never fail */\r
+ return IRQ_HANDLED;\r
+ }\r
+\r
+ return dws->transfer_handler(dws);\r
+}\r
+\r
+/* Must be called inside pump_transfers() */\r
+static void poll_transfer(struct rk29xx_spi *dws)\r
+{\r
+ DBG(KERN_INFO "poll_transfer\n");\r
+ while (dws->write(dws)) {\r
+ wait_till_not_busy(dws);\r
+ dws->read(dws);\r
+ }\r
+ transfer_complete(dws);\r
+}\r
+\r
+static void dma_transfer(struct rk29xx_spi *dws, struct spi_transfer *xfer) //int cs_change)\r
+{\r
+ unsigned long val;\r
+ int ms;\r
+\r
+ DBG(KERN_INFO "dma_transfer\n");\r
+ \r
+ if (xfer->tx_buf != NULL) {\r
+ dws->state |= TXBUSY;\r
+ rk29_dma_config(dws->tx_dmach, 4);\r
+ rk29_dma_enqueue(dws->tx_dmach, (void *)dws,\r
+ xfer->tx_dma, xfer->len);\r
+ rk29_dma_ctrl(dws->tx_dmach, RK29_DMAOP_START);\r
+ }\r
+\r
+ if (xfer->rx_buf != NULL) {\r
+ dws->state |= RXBUSY;\r
+ rk29_dma_config(dws->rx_dmach, 4);\r
+ rk29_dma_enqueue(dws->rx_dmach, (void *)dws,\r
+ xfer->rx_dma, xfer->len);\r
+ rk29_dma_ctrl(dws->rx_dmach, RK29_DMAOP_START);\r
+ }\r
+\r
+ /* millisecs to xfer 'len' bytes @ 'cur_speed' */\r
+ ms = xfer->len * 8 * 1000 / dws->cur_speed;\r
+ ms += 10; /* some tolerance */\r
+\r
+ val = msecs_to_jiffies(ms) + 10;\r
+ val = wait_for_completion_timeout(&dws->xfer_completion, val);\r
+}\r
+\r
+static void spi_chip_sel(struct rk29xx_spi *dws, u16 cs)\r
+{\r
+ if(cs >= dws->master->num_chipselect)\r
+ return;\r
+\r
+ if (dws->cs_control){\r
+ dws->cs_control(dws, cs, 1);\r
+ }\r
+ rk29xx_writel(dws, SPIM_SER, 1 << cs);\r
+}\r
+\r
+static void pump_transfers(unsigned long data)\r
+{\r
+ struct rk29xx_spi *dws = (struct rk29xx_spi *)data;\r
+ struct spi_message *message = NULL;\r
+ struct spi_transfer *transfer = NULL;\r
+ struct spi_transfer *previous = NULL;\r
+ struct spi_device *spi = NULL;\r
+ struct chip_data *chip = NULL;\r
+ u8 bits = 0;\r
+ u8 spi_dfs = 0;\r
+ u8 imask = 0;\r
+ u8 cs_change = 0;\r
+ u16 txint_level = 0;\r
+ u16 clk_div = 0;\r
+ u32 speed = 0;\r
+ u32 cr0 = 0;\r
+\r
+ DBG(KERN_INFO "pump_transfers");\r
+\r
+ /* Get current state information */\r
+ message = dws->cur_msg;\r
+ transfer = dws->cur_transfer;\r
+ chip = dws->cur_chip;\r
+ spi = message->spi; \r
+ if (unlikely(!chip->clk_div))\r
+ chip->clk_div = clk_get_rate(dws->clock_spim) / chip->speed_hz; \r
+ if (message->state == ERROR_STATE) {\r
+ message->status = -EIO;\r
+ goto early_exit;\r
+ }\r
+\r
+ /* Handle end of message */\r
+ if (message->state == DONE_STATE) {\r
+ message->status = 0;\r
+ goto early_exit;\r
+ }\r
+\r
+ /* Delay if requested at end of transfer*/\r
+ if (message->state == RUNNING_STATE) {\r
+ previous = list_entry(transfer->transfer_list.prev,\r
+ struct spi_transfer,\r
+ transfer_list);\r
+ if (previous->delay_usecs)\r
+ udelay(previous->delay_usecs);\r
+ }\r
+\r
+ dws->n_bytes = chip->n_bytes;\r
+ dws->dma_width = chip->dma_width;\r
+ dws->cs_control = chip->cs_control;\r
+\r
+ dws->rx_dma = transfer->rx_dma;\r
+ dws->tx_dma = transfer->tx_dma;\r
+ dws->tx = (void *)transfer->tx_buf;\r
+ dws->tx_end = dws->tx + transfer->len;\r
+ dws->rx = transfer->rx_buf;\r
+ dws->rx_end = dws->rx + transfer->len;\r
+ dws->write = dws->tx ? chip->write : null_writer;\r
+ dws->read = dws->rx ? chip->read : null_reader;\r
+ dws->cs_change = transfer->cs_change;\r
+ dws->len = dws->cur_transfer->len;\r
+ if (chip != dws->prev_chip)\r
+ cs_change = 1;\r
+\r
+ cr0 = chip->cr0;\r
+\r
+ /* Handle per transfer options for bpw and speed */\r
+ if (transfer->speed_hz) {\r
+ speed = chip->speed_hz;\r
+\r
+ if (transfer->speed_hz != speed) {\r
+ speed = transfer->speed_hz;\r
+ if (speed > clk_get_rate(dws->clock_spim)) {\r
+ dev_err(&dws->master->dev, "MRST SPI0: unsupported"\r
+ "freq: %dHz\n", speed);\r
+ message->status = -EIO;\r
+ goto early_exit;\r
+ }\r
+\r
+ /* clk_div doesn't support odd number */\r
+ clk_div = clk_get_rate(dws->clock_spim) / speed;\r
+ clk_div = (clk_div + 1) & 0xfffe;\r
+\r
+ chip->speed_hz = speed;\r
+ chip->clk_div = clk_div;\r
+ }\r
+ }\r
+ if (transfer->bits_per_word) {\r
+ bits = transfer->bits_per_word;\r
+\r
+ switch (bits) {\r
+ case 8:\r
+ dws->n_bytes = 1;\r
+ dws->dma_width = 1;\r
+ dws->read = (dws->read != null_reader) ?\r
+ u8_reader : null_reader;\r
+ dws->write = (dws->write != null_writer) ?\r
+ u8_writer : null_writer;\r
+ spi_dfs = SPI_DFS_8BIT;\r
+ break;\r
+ case 16:\r
+ dws->n_bytes = 2;\r
+ dws->dma_width = 2;\r
+ dws->read = (dws->read != null_reader) ?\r
+ u16_reader : null_reader;\r
+ dws->write = (dws->write != null_writer) ?\r
+ u16_writer : null_writer;\r
+ spi_dfs = SPI_DFS_16BIT;\r
+ break;\r
+ default:\r
+ dev_err(&dws->master->dev, "MRST SPI0: unsupported bits:"\r
+ "%db\n", bits);\r
+ message->status = -EIO;\r
+ goto early_exit;\r
+ }\r
+\r
+ cr0 = (spi_dfs << SPI_DFS_OFFSET)\r
+ | (chip->type << SPI_FRF_OFFSET)\r
+ | (spi->mode << SPI_MODE_OFFSET)\r
+ | (chip->tmode << SPI_TMOD_OFFSET);\r
+ }\r
+ message->state = RUNNING_STATE;\r
+ \r
+ /*\r
+ * Adjust transfer mode if necessary. Requires platform dependent\r
+ * chipselect mechanism.\r
+ */\r
+ if (dws->cs_control) {\r
+ if (dws->rx && dws->tx)\r
+ chip->tmode = SPI_TMOD_TR;\r
+ else if (dws->rx)\r
+ chip->tmode = SPI_TMOD_RO;\r
+ else\r
+ chip->tmode = SPI_TMOD_TO;\r
+\r
+ cr0 &= ~(0x3 << SPI_MODE_OFFSET);\r
+ cr0 |= (chip->tmode << SPI_TMOD_OFFSET);\r
+ }\r
+ /* Check if current transfer is a DMA transaction */\r
+ dws->dma_mapped = map_dma_buffers(dws);\r
+\r
+ /*\r
+ * Interrupt mode\r
+ * we only need set the TXEI IRQ, as TX/RX always happen syncronizely\r
+ */\r
+ if (!dws->dma_mapped && !chip->poll_mode) {\r
+ int templen = dws->len / dws->n_bytes;\r
+ txint_level = dws->fifo_len / 2;\r
+ txint_level = (templen > txint_level) ? txint_level : templen;\r
+\r
+ imask |= SPI_INT_TXEI;\r
+ dws->transfer_handler = interrupt_transfer;\r
+ }\r
+\r
+ /*\r
+ * Reprogram registers only if\r
+ * 1. chip select changes\r
+ * 2. clk_div is changed\r
+ * 3. control value changes\r
+ */\r
+ if (rk29xx_readw(dws, SPIM_CTRLR0) != cr0 || cs_change || clk_div || imask) {\r
+ spi_enable_chip(dws, 0);\r
+ if (rk29xx_readw(dws, SPIM_CTRLR0) != cr0)\r
+ rk29xx_writew(dws, SPIM_CTRLR0, cr0);\r
+\r
+ spi_set_clk(dws, clk_div ? clk_div : chip->clk_div); \r
+ spi_chip_sel(dws, spi->chip_select);\r
+ /* Set the interrupt mask, for poll mode just diable all int */\r
+ spi_mask_intr(dws, 0xff);\r
+ if (imask)\r
+ spi_umask_intr(dws, imask);\r
+ if (txint_level)\r
+ rk29xx_writew(dws, SPIM_TXFTLR, txint_level);\r
+\r
+ spi_enable_chip(dws, 1);\r
+ if (cs_change)\r
+ dws->prev_chip = chip;\r
+ }\r
+\r
+ if (dws->dma_mapped && transfer->len > DMA_MIN_BYTES)\r
+ dma_transfer(dws, transfer); ///cs_change);\r
+\r
+ if (chip->poll_mode)\r
+ poll_transfer(dws);\r
+\r
+ return;\r
+\r
+early_exit:\r
+ giveback(dws);\r
+ return;\r
+}\r
+\r
+static void pump_messages(struct work_struct *work)\r
+{\r
+ struct rk29xx_spi *dws =\r
+ container_of(work, struct rk29xx_spi, pump_messages);\r
+ unsigned long flags;\r
+\r
+ DBG(KERN_INFO "pump_messages\n");\r
+\r
+ while (!acquire_dma(dws))\r
+ msleep(10);\r
+\r
+ /* Lock queue and check for queue work */\r
+ spin_lock_irqsave(&dws->lock, flags);\r
+ if (list_empty(&dws->queue) || dws->run == QUEUE_STOPPED) {\r
+ dws->busy = 0;\r
+ spin_unlock_irqrestore(&dws->lock, flags);\r
+ return;\r
+ }\r
+\r
+ /* Make sure we are not already running a message */\r
+ if (dws->cur_msg) {\r
+ spin_unlock_irqrestore(&dws->lock, flags);\r
+ return;\r
+ }\r
+\r
+ /* Extract head of queue */\r
+ dws->cur_msg = list_entry(dws->queue.next, struct spi_message, queue);\r
+ list_del_init(&dws->cur_msg->queue);\r
+\r
+ /* Initial message state*/\r
+ dws->cur_msg->state = START_STATE;\r
+ dws->cur_transfer = list_entry(dws->cur_msg->transfers.next,\r
+ struct spi_transfer,\r
+ transfer_list);\r
+ dws->cur_chip = spi_get_ctldata(dws->cur_msg->spi);\r
+ dws->prev_chip = NULL; //ÿ¸öpump messageʱǿÖƸüÐÂcs dxj\r
+ \r
+ /* Mark as busy and launch transfers */\r
+ tasklet_schedule(&dws->pump_transfers);\r
+\r
+ dws->busy = 1;\r
+ spin_unlock_irqrestore(&dws->lock, flags);\r
+}\r
+\r
+#if defined(QUICK_TRANSFER)\r
+static void do_read(struct rk29xx_spi *dws)\r
+{\r
+ int count = 0;\r
+\r
+ spi_enable_chip(dws, 0);\r
+ rk29xx_writew(dws, SPIM_CTRLR1, dws->rx_end-dws->rx-1);\r
+ spi_enable_chip(dws, 1); \r
+ rk29xx_writew(dws, SPIM_TXDR, 0);\r
+ while (1) {\r
+ if (dws->read(dws))\r
+ break;\r
+ if (count ++ == 0x20) {\r
+ dev_err(&dws->master->dev, "+++++++++++spi receive data time out+++++++++++++\n");\r
+ break;\r
+ }\r
+ \r
+ }\r
+}\r
+\r
+static void do_write(struct rk29xx_spi *dws)\r
+{\r
+ while (dws->tx<dws->tx_end) {\r
+ dws->write(dws);\r
+ }\r
+}\r
+\r
+/* Caller already set message->status; dma and pio irqs are blocked */\r
+static void msg_giveback(struct rk29xx_spi *dws)\r
+{\r
+ struct spi_transfer *last_transfer;\r
+ struct spi_message *msg;\r
+\r
+ DBG("+++++++++++++++enter %s++++++++++++++++++\n", __func__);\r
+\r
+ msg = dws->cur_msg;\r
+ dws->cur_msg = NULL;\r
+ dws->cur_transfer = NULL;\r
+ dws->prev_chip = dws->cur_chip;\r
+ dws->cur_chip = NULL;\r
+ dws->dma_mapped = 0;\r
+ dws->busy = 0;\r
+\r
+ last_transfer = list_entry(msg->transfers.prev,\r
+ struct spi_transfer,\r
+ transfer_list);\r
+\r
+ if (!last_transfer->cs_change)\r
+ dws->cs_control(dws,msg->spi->chip_select,MRST_SPI_DEASSERT);\r
+\r
+ msg->state = NULL; \r
+}\r
+\r
+/* Must be called inside pump_transfers() */\r
+static int do_full_transfer(struct rk29xx_spi *dws)\r
+{\r
+ if ((dws->read(dws))) {\r
+ goto comple;\r
+ }\r
+ \r
+ while (dws->tx<dws->tx_end){\r
+ dws->write(dws); \r
+ dws->read(dws);\r
+ }\r
+ \r
+ if (dws->rx < dws->rx_end) {\r
+ dws->read(dws);\r
+ }\r
+\r
+comple:\r
+ \r
+ dws->cur_msg->actual_length += dws->len;\r
+ \r
+ /* Move to next transfer */\r
+ dws->cur_msg->state = next_transfer(dws);\r
+ \r
+ if (dws->cur_msg->state == DONE_STATE) {\r
+ dws->cur_msg->status = 0;\r
+ //msg_giveback(dws);\r
+ return 0;\r
+ }\r
+ else {\r
+ return -1;\r
+ }\r
+ \r
+}\r
+\r
+\r
+/* Must be called inside pump_transfers() */\r
+static int do_half_transfer(struct rk29xx_spi *dws)\r
+{\r
+ if (dws->rx) {\r
+ if (dws->tx) {\r
+ do_write(dws);\r
+ }\r
+ wait_till_tf_empty(dws);\r
+ wait_till_not_busy(dws);\r
+ do_read(dws);\r
+ }\r
+ else {\r
+ do_write(dws);\r
+ wait_till_tf_empty(dws);\r
+ wait_till_not_busy(dws);\r
+ }\r
+ \r
+ dws->cur_msg->actual_length += dws->len;\r
+ \r
+ /* Move to next transfer */\r
+ dws->cur_msg->state = next_transfer(dws);\r
+ \r
+ if (dws->cur_msg->state == DONE_STATE) {\r
+ dws->cur_msg->status = 0;\r
+ //msg_giveback(dws);\r
+ return 0;\r
+ }\r
+ else {\r
+ return -1;\r
+ }\r
+}\r
+\r
+\r
+static int rk29xx_pump_transfers(struct rk29xx_spi *dws, int mode)\r
+{\r
+ struct spi_message *message = NULL;\r
+ struct spi_transfer *transfer = NULL;\r
+ struct spi_transfer *previous = NULL;\r
+ struct spi_device *spi = NULL;\r
+ struct chip_data *chip = NULL;\r
+ u8 bits = 0;\r
+ u8 spi_dfs = 0;\r
+ u8 cs_change = 0;\r
+ u16 clk_div = 0;\r
+ u32 speed = 0;\r
+ u32 cr0 = 0;\r
+ u32 dmacr = 0;\r
+ \r
+ DBG(KERN_INFO "+++++++++++++++enter %s++++++++++++++++++\n", __func__);\r
+\r
+ /* Get current state information */\r
+ message = dws->cur_msg;\r
+ transfer = dws->cur_transfer;\r
+ chip = dws->cur_chip;\r
+ spi = message->spi; \r
+\r
+ if (unlikely(!chip->clk_div)) {\r
+ chip->clk_div = clk_get_rate(dws->clock_spim) / chip->speed_hz;\r
+ chip->clk_div = (chip->clk_div + 1) & 0xfffe;\r
+ }\r
+ if (message->state == ERROR_STATE) {\r
+ message->status = -EIO;\r
+ goto early_exit;\r
+ }\r
+\r
+ /* Handle end of message */\r
+ if (message->state == DONE_STATE) {\r
+ message->status = 0;\r
+ goto early_exit;\r
+ }\r
+\r
+ /* Delay if requested at end of transfer*/\r
+ if (message->state == RUNNING_STATE) {\r
+ previous = list_entry(transfer->transfer_list.prev,\r
+ struct spi_transfer,\r
+ transfer_list);\r
+ if (previous->delay_usecs)\r
+ udelay(previous->delay_usecs);\r
+ }\r
+\r
+ dws->n_bytes = chip->n_bytes;\r
+ dws->dma_width = chip->dma_width;\r
+ dws->cs_control = chip->cs_control;\r
+\r
+ dws->rx_dma = transfer->rx_dma;\r
+ dws->tx_dma = transfer->tx_dma;\r
+ dws->tx = (void *)transfer->tx_buf;\r
+ dws->tx_end = dws->tx + transfer->len;\r
+ dws->rx = transfer->rx_buf;\r
+ dws->rx_end = dws->rx + transfer->len;\r
+ dws->write = dws->tx ? chip->write : null_writer;\r
+ dws->read = dws->rx ? chip->read : null_reader;\r
+ if (dws->rx && dws->tx) {\r
+ int temp_len = transfer->len;\r
+ int len;\r
+ unsigned char *tx_buf;\r
+ for (len=0; *tx_buf++ != 0; len++);\r
+ dws->tx_end = dws->tx + len;\r
+ dws->rx_end = dws->rx + temp_len - len;\r
+ }\r
+ dws->cs_change = transfer->cs_change;\r
+ dws->len = dws->cur_transfer->len;\r
+ if (chip != dws->prev_chip)\r
+ cs_change = 1;\r
+\r
+ cr0 = chip->cr0;\r
+\r
+ /* Handle per transfer options for bpw and speed */\r
+ if (transfer->speed_hz) {\r
+ speed = chip->speed_hz;\r
+\r
+ if (transfer->speed_hz != speed) {\r
+ speed = transfer->speed_hz;\r
+ if (speed > clk_get_rate(dws->clock_spim)) {\r
+ dev_err(&dws->master->dev, "MRST SPI0: unsupported"\r
+ "freq: %dHz\n", speed);\r
+ message->status = -EIO;\r
+ goto early_exit;\r
+ }\r
+\r
+ /* clk_div doesn't support odd number */\r
+ clk_div = clk_get_rate(dws->clock_spim) / speed;\r
+ clk_div = (clk_div + 1) & 0xfffe;\r
+\r
+ chip->speed_hz = speed;\r
+ chip->clk_div = clk_div;\r
+ }\r
+ }\r
+ if (transfer->bits_per_word) {\r
+ bits = transfer->bits_per_word;\r
+\r
+ switch (bits) {\r
+ case 8:\r
+ dws->n_bytes = 1;\r
+ dws->dma_width = 1;\r
+ dws->read = (dws->read != null_reader) ?\r
+ u8_reader : null_reader;\r
+ dws->write = (dws->write != null_writer) ?\r
+ u8_writer : null_writer;\r
+ spi_dfs = SPI_DFS_8BIT;\r
+ break;\r
+ case 16:\r
+ dws->n_bytes = 2;\r
+ dws->dma_width = 2;\r
+ dws->read = (dws->read != null_reader) ?\r
+ u16_reader : null_reader;\r
+ dws->write = (dws->write != null_writer) ?\r
+ u16_writer : null_writer;\r
+ spi_dfs = SPI_DFS_16BIT;\r
+ break;\r
+ default:\r
+ dev_err(&dws->master->dev, "MRST SPI0: unsupported bits:"\r
+ "%db\n", bits);\r
+ message->status = -EIO;\r
+ goto early_exit;\r
+ }\r
+\r
+ cr0 = (spi_dfs << SPI_DFS_OFFSET)\r
+ | (chip->type << SPI_FRF_OFFSET)\r
+ | (spi->mode << SPI_MODE_OFFSET)\r
+ | (chip->tmode << SPI_TMOD_OFFSET);\r
+ }\r
+ message->state = RUNNING_STATE;\r
+ \r
+ /*\r
+ * Adjust transfer mode if necessary. Requires platform dependent\r
+ * chipselect mechanism.\r
+ */\r
+ if (dws->cs_control) {\r
+ if (dws->rx && dws->tx)\r
+ chip->tmode = SPI_TMOD_TR;\r
+ else if (dws->rx)\r
+ chip->tmode = SPI_TMOD_RO;\r
+ else\r
+ chip->tmode = SPI_TMOD_TO;\r
+\r
+ cr0 &= ~(0x3 << SPI_MODE_OFFSET);\r
+ cr0 |= (chip->tmode << SPI_TMOD_OFFSET);\r
+ }\r
+ \r
+ /* Check if current transfer is a DMA transaction */\r
+ dws->dma_mapped = map_dma_buffers(dws);\r
+\r
+ /*\r
+ * Reprogram registers only if\r
+ * 1. chip select changes\r
+ * 2. clk_div is changed\r
+ * 3. control value changes\r
+ */\r
+ spi_enable_chip(dws, 0);\r
+ if (rk29xx_readw(dws, SPIM_CTRLR0) != cr0)\r
+ rk29xx_writew(dws, SPIM_CTRLR0, cr0);\r
+\r
+ DBG(KERN_INFO "clk_div: 0x%x, chip->clk_div: 0x%x\n", clk_div, chip->clk_div);\r
+ spi_set_clk(dws, clk_div ? clk_div : chip->clk_div); \r
+ spi_chip_sel(dws, spi->chip_select); \r
+ rk29xx_writew(dws, SPIM_CTRLR1, 0);//add by lyx\r
+ if(dws->dma_mapped ) {\r
+ dmacr = rk29xx_readw(dws, SPIM_DMACR);\r
+ dmacr = dmacr | SPI_DMACR_TX_ENABLE;\r
+ if (mode) \r
+ dmacr = dmacr | SPI_DMACR_RX_ENABLE;\r
+ rk29xx_writew(dws, SPIM_DMACR, dmacr);\r
+ }\r
+ spi_enable_chip(dws, 1);\r
+ if (cs_change)\r
+ dws->prev_chip = chip;\r
+ \r
+ if (dws->dma_mapped && transfer->len > DMA_MIN_BYTES) {\r
+ dma_transfer(dws, transfer);\r
+ }\r
+ else {\r
+ if (mode)\r
+ return do_full_transfer(dws);\r
+ else\r
+ return do_half_transfer(dws);\r
+ }\r
+ \r
+early_exit:\r
+ \r
+ //msg_giveback(dws);\r
+ \r
+ return 0;\r
+}\r
+\r
+static void rk29xx_pump_messages(struct rk29xx_spi *dws, int mode)\r
+{\r
+ DBG(KERN_INFO "+++++++++++++++enter %s++++++++++++++++++\n", __func__);\r
+ \r
+ while (!acquire_dma(dws))\r
+ msleep(10);\r
+\r
+ if (list_empty(&dws->queue) || dws->run == QUEUE_STOPPED) {\r
+ dws->busy = 0;\r
+ return;\r
+ }\r
+\r
+ /* Make sure we are not already running a message */\r
+ if (dws->cur_msg) {\r
+ return;\r
+ }\r
+\r
+ /* Extract head of queue */\r
+ dws->cur_msg = list_entry(dws->queue.next, struct spi_message, queue);\r
+ list_del_init(&dws->cur_msg->queue);\r
+\r
+ /* Initial message state*/\r
+ dws->cur_msg->state = START_STATE;\r
+ dws->cur_transfer = list_entry(dws->cur_msg->transfers.next,\r
+ struct spi_transfer,\r
+ transfer_list);\r
+ dws->cur_chip = spi_get_ctldata(dws->cur_msg->spi);\r
+ dws->prev_chip = NULL; //ÿ¸öpump messageʱǿÖƸüÐÂcs dxj\r
+ \r
+ /* Mark as busy and launch transfers */\r
+ dws->busy = 1;\r
+\r
+ while (rk29xx_pump_transfers(dws, mode)) ;\r
+}\r
+\r
+/* spi_device use this to queue in their spi_msg */\r
+static int rk29xx_spi_quick_transfer(struct spi_device *spi, struct spi_message *msg)\r
+{\r
+ struct rk29xx_spi *dws = spi_master_get_devdata(spi->master);\r
+ unsigned long flags;\r
+ struct rk29xx_spi_chip *chip_info = spi->controller_data;\r
+ struct spi_message *mmsg;\r
+ \r
+ DBG(KERN_INFO "+++++++++++++++enter %s++++++++++++++++++\n", __func__);\r
+ \r
+ spin_lock_irqsave(&dws->lock, flags);\r
+\r
+ if (dws->run == QUEUE_STOPPED) {\r
+ spin_unlock_irqrestore(&dws->lock, flags);\r
+ return -ESHUTDOWN;\r
+ }\r
+\r
+ msg->actual_length = 0;\r
+ msg->status = -EINPROGRESS;\r
+ msg->state = START_STATE;\r
+\r
+ list_add_tail(&msg->queue, &dws->queue);\r
+\r
+ if (chip_info && (chip_info->transfer_mode == rk29xx_SPI_FULL_DUPLEX)) {\r
+ rk29xx_pump_messages(dws,1);\r
+ }\r
+ else { \r
+ rk29xx_pump_messages(dws,0);\r
+ }\r
+\r
+ mmsg = dws->cur_msg;\r
+ msg_giveback(dws);\r
+ \r
+ spin_unlock_irqrestore(&dws->lock, flags);\r
+\r
+ if (mmsg->complete)\r
+ mmsg->complete(mmsg->context);\r
+ \r
+ return 0;\r
+}\r
+\r
+#else\r
+\r
+/* spi_device use this to queue in their spi_msg */\r
+static int rk29xx_spi_transfer(struct spi_device *spi, struct spi_message *msg)\r
+{\r
+ struct rk29xx_spi *dws = spi_master_get_devdata(spi->master);\r
+ unsigned long flags;\r
+\r
+ spin_lock_irqsave(&dws->lock, flags);\r
+\r
+ if (dws->run == QUEUE_STOPPED) {\r
+ spin_unlock_irqrestore(&dws->lock, flags);\r
+ return -ESHUTDOWN;\r
+ }\r
+\r
+ msg->actual_length = 0;\r
+ msg->status = -EINPROGRESS;\r
+ msg->state = START_STATE;\r
+\r
+ list_add_tail(&msg->queue, &dws->queue);\r
+\r
+ if (dws->run == QUEUE_RUNNING && !dws->busy) {\r
+\r
+ if (dws->cur_transfer || dws->cur_msg)\r
+ queue_work(dws->workqueue,\r
+ &dws->pump_messages);\r
+ else {\r
+ /* If no other data transaction in air, just go */\r
+ spin_unlock_irqrestore(&dws->lock, flags);\r
+ pump_messages(&dws->pump_messages);\r
+ return 0;\r
+ }\r
+ }\r
+\r
+ spin_unlock_irqrestore(&dws->lock, flags);\r
+ \r
+ return 0;\r
+}\r
+\r
+#endif\r
+\r
+/* This may be called twice for each spi dev */\r
+static int rk29xx_spi_setup(struct spi_device *spi)\r
+{\r
+ struct rk29xx_spi_chip *chip_info = NULL;\r
+ struct chip_data *chip;\r
+ u8 spi_dfs = 0;\r
+\r
+ if (spi->bits_per_word != 8 && spi->bits_per_word != 16)\r
+ return -EINVAL;\r
+\r
+ /* Only alloc on first setup */\r
+ chip = spi_get_ctldata(spi);\r
+ if (!chip) {\r
+ chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);\r
+ if (!chip)\r
+ return -ENOMEM;\r
+\r
+ chip->cs_control = spi_cs_control;\r
+ chip->enable_dma = 1; //0;\r
+ }\r
+\r
+ /*\r
+ * Protocol drivers may change the chip settings, so...\r
+ * if chip_info exists, use it\r
+ */\r
+ chip_info = spi->controller_data;\r
+\r
+ /* chip_info doesn't always exist */\r
+ if (chip_info) {\r
+ if (chip_info->cs_control)\r
+ chip->cs_control = chip_info->cs_control;\r
+\r
+ chip->poll_mode = chip_info->poll_mode;\r
+ chip->type = chip_info->type;\r
+\r
+ chip->rx_threshold = 0;\r
+ chip->tx_threshold = 0;\r
+\r
+ chip->enable_dma = chip_info->enable_dma;\r
+ }\r
+\r
+ if (spi->bits_per_word == 8) {\r
+ chip->n_bytes = 1;\r
+ chip->dma_width = 1;\r
+ chip->read = u8_reader;\r
+ chip->write = u8_writer;\r
+ spi_dfs = SPI_DFS_8BIT;\r
+ } else if (spi->bits_per_word == 16) {\r
+ chip->n_bytes = 2;\r
+ chip->dma_width = 2;\r
+ chip->read = u16_reader;\r
+ chip->write = u16_writer;\r
+ spi_dfs = SPI_DFS_16BIT;\r
+ } else {\r
+ /* Never take >16b case for MRST SPIC */\r
+ dev_err(&spi->dev, "invalid wordsize\n");\r
+ return -EINVAL;\r
+ }\r
+ chip->bits_per_word = spi->bits_per_word;\r
+\r
+ if (!spi->max_speed_hz) {\r
+ dev_err(&spi->dev, "No max speed HZ parameter\n");\r
+ return -EINVAL;\r
+ }\r
+ chip->speed_hz = spi->max_speed_hz;\r
+\r
+ chip->tmode = 0; /* Tx & Rx */\r
+ /* Default SPI mode is SCPOL = 0, SCPH = 0 */\r
+ chip->cr0 = (spi_dfs << SPI_DFS_OFFSET)\r
+ | (chip->type << SPI_FRF_OFFSET)\r
+ | (spi->mode << SPI_MODE_OFFSET)\r
+ | (chip->tmode << SPI_TMOD_OFFSET);\r
+\r
+ spi_set_ctldata(spi, chip);\r
+ return 0;\r
+}\r
+\r
+static void rk29xx_spi_cleanup(struct spi_device *spi)\r
+{\r
+ struct chip_data *chip = spi_get_ctldata(spi);\r
+ kfree(chip);\r
+}\r
+\r
+static int __devinit init_queue(struct rk29xx_spi *dws)\r
+{\r
+ INIT_LIST_HEAD(&dws->queue);\r
+ spin_lock_init(&dws->lock);\r
+\r
+ dws->run = QUEUE_STOPPED;\r
+ dws->busy = 0;\r
+\r
+ tasklet_init(&dws->pump_transfers,\r
+ pump_transfers, (unsigned long)dws);\r
+\r
+ INIT_WORK(&dws->pump_messages, pump_messages);\r
+ dws->workqueue = create_singlethread_workqueue(\r
+ dev_name(dws->master->dev.parent));\r
+ if (dws->workqueue == NULL)\r
+ return -EBUSY;\r
+\r
+ return 0;\r
+}\r
+\r
+static int start_queue(struct rk29xx_spi *dws)\r
+{\r
+ unsigned long flags;\r
+\r
+ spin_lock_irqsave(&dws->lock, flags);\r
+\r
+ if (dws->run == QUEUE_RUNNING || dws->busy) {\r
+ spin_unlock_irqrestore(&dws->lock, flags);\r
+ return -EBUSY;\r
+ }\r
+\r
+ dws->run = QUEUE_RUNNING;\r
+ dws->cur_msg = NULL;\r
+ dws->cur_transfer = NULL;\r
+ dws->cur_chip = NULL;\r
+ dws->prev_chip = NULL;\r
+ spin_unlock_irqrestore(&dws->lock, flags);\r
+\r
+ queue_work(dws->workqueue, &dws->pump_messages);\r
+\r
+ return 0;\r
+}\r
+\r
+static int stop_queue(struct rk29xx_spi *dws)\r
+{\r
+ unsigned long flags;\r
+ unsigned limit = 50;\r
+ int status = 0;\r
+\r
+ spin_lock_irqsave(&dws->lock, flags);\r
+ dws->run = QUEUE_STOPPED;\r
+ while (!list_empty(&dws->queue) && dws->busy && limit--) {\r
+ spin_unlock_irqrestore(&dws->lock, flags);\r
+ msleep(10);\r
+ spin_lock_irqsave(&dws->lock, flags);\r
+ }\r
+\r
+ if (!list_empty(&dws->queue) || dws->busy)\r
+ status = -EBUSY;\r
+ spin_unlock_irqrestore(&dws->lock, flags);\r
+\r
+ return status;\r
+}\r
+\r
+static int destroy_queue(struct rk29xx_spi *dws)\r
+{\r
+ int status;\r
+\r
+ status = stop_queue(dws);\r
+ if (status != 0)\r
+ return status;\r
+ destroy_workqueue(dws->workqueue);\r
+ return 0;\r
+}\r
+\r
+/* Restart the controller, disable all interrupts, clean rx fifo */\r
+static void spi_hw_init(struct rk29xx_spi *dws)\r
+{\r
+ spi_enable_chip(dws, 0);\r
+ spi_mask_intr(dws, 0xff);\r
+ spi_enable_chip(dws, 1);\r
+ flush(dws);\r
+\r
+ /*\r
+ * Try to detect the FIFO depth if not set by interface driver,\r
+ * the depth could be from 2 to 32 from HW spec\r
+ */\r
+ if (!dws->fifo_len) {\r
+ u32 fifo;\r
+ for (fifo = 2; fifo <= 31; fifo++) {\r
+ rk29xx_writew(dws, SPIM_TXFTLR, fifo);\r
+ if (fifo != rk29xx_readw(dws, SPIM_TXFTLR))\r
+ break;\r
+ }\r
+\r
+ dws->fifo_len = (fifo == 31) ? 0 : fifo;\r
+ rk29xx_writew(dws, SPIM_TXFTLR, 0);\r
+ }\r
+}\r
+\r
+/* cpufreq driver support */\r
+#ifdef CONFIG_CPU_FREQ\r
+\r
+static int rk29xx_spim_cpufreq_transition(struct notifier_block *nb, unsigned long val, void *data)\r
+{\r
+ struct rk29xx_spi *info;\r
+ unsigned long newclk;\r
+\r
+ info = container_of(nb, struct rk29xx_spi, freq_transition);\r
+ newclk = clk_get_rate(info->clock_spim);\r
+\r
+ return 0;\r
+}\r
+\r
+static inline int rk29xx_spim_cpufreq_register(struct rk29xx_spi *info)\r
+{\r
+ info->freq_transition.notifier_call = rk29xx_spim_cpufreq_transition;\r
+\r
+ return cpufreq_register_notifier(&info->freq_transition, CPUFREQ_TRANSITION_NOTIFIER);\r
+}\r
+\r
+static inline void rk29xx_spim_cpufreq_deregister(struct rk29xx_spi *info)\r
+{\r
+ cpufreq_unregister_notifier(&info->freq_transition, CPUFREQ_TRANSITION_NOTIFIER);\r
+}\r
+\r
+#else\r
+static inline int rk29xx_spim_cpufreq_register(struct rk29xx_spi *info)\r
+{\r
+ return 0;\r
+}\r
+\r
+static inline void rk29xx_spim_cpufreq_deregister(struct rk29xx_spi *info)\r
+{\r
+}\r
+#endif\r
+static int __init rk29xx_spim_probe(struct platform_device *pdev)\r
+{\r
+ struct resource *regs, *dmatx_res, *dmarx_res;\r
+ struct rk29xx_spi *dws;\r
+ struct spi_master *master;\r
+ int irq; \r
+ int ret;\r
+ struct rk29xx_spi_platform_data *pdata = pdev->dev.platform_data;\r
+ char szBuf[8];\r
+\r
+ if (pdata && pdata->io_init) {\r
+ ret = pdata->io_init(pdata->chipselect_gpios, pdata->num_chipselect);\r
+ if (ret) { \r
+ return -ENXIO; \r
+ }\r
+ }\r
+ \r
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);\r
+ if (!regs)\r
+ return -ENXIO;\r
+ dmatx_res = platform_get_resource(pdev, IORESOURCE_DMA, 0);\r
+ if (dmatx_res == NULL) {\r
+ dev_err(&pdev->dev, "Unable to get SPI-Tx dma resource\n");\r
+ return -ENXIO;\r
+ }\r
+\r
+ dmarx_res = platform_get_resource(pdev, IORESOURCE_DMA, 1);\r
+ if (dmarx_res == NULL) {\r
+ dev_err(&pdev->dev, "Unable to get SPI-Rx dma resource\n");\r
+ return -ENXIO;\r
+ }\r
+ irq = platform_get_irq(pdev, 0);\r
+ if (irq < 0)\r
+ return irq; \r
+ /* setup spi core then atmel-specific driver state */\r
+ ret = -ENOMEM; \r
+ master = spi_alloc_master(&pdev->dev, sizeof *dws);\r
+ if (!master) {\r
+ ret = -ENOMEM;\r
+ goto exit;\r
+ }\r
+\r
+ platform_set_drvdata(pdev, master);\r
+ dws = spi_master_get_devdata(master);\r
+ memset(szBuf, 0, sizeof(szBuf));\r
+ sprintf(szBuf, "%s%d", "spi", pdev->id);\r
+ dws->clock_spim = clk_get(&pdev->dev, szBuf);\r
+ clk_enable(dws->clock_spim);\r
+ if (IS_ERR(dws->clock_spim)) {\r
+ dev_err(&pdev->dev, "clk_get for %s fail(%p)\n", szBuf, dws->clock_spim);\r
+ return PTR_ERR(dws->clock_spim);\r
+ }\r
+ \r
+ dws->regs = ioremap(regs->start, (regs->end - regs->start) + 1);\r
+ if (!dws->regs){\r
+ release_mem_region(regs->start, (regs->end - regs->start) + 1);\r
+ return -EBUSY;\r
+ }\r
+ DBG(KERN_INFO "dws->regs: %p\n", dws->regs);\r
+ dws->irq = irq;\r
+ dws->irq_polarity = IRQF_TRIGGER_NONE;\r
+ dws->master = master;\r
+ dws->type = SSI_MOTO_SPI;\r
+ dws->prev_chip = NULL;\r
+ dws->sfr_start = regs->start;\r
+ dws->tx_dmach = dmatx_res->start;\r
+ dws->rx_dmach = dmarx_res->start;\r
+ dws->dma_inited = 0; ///0;\r
+ ///dws->dma_addr = (dma_addr_t)(dws->paddr + 0x60);\r
+ ret = request_irq(dws->irq, rk29xx_spi_irq, dws->irq_polarity,\r
+ "rk29xx_spim", dws);\r
+ if (ret < 0) {\r
+ dev_err(&master->dev, "can not get IRQ\n");\r
+ goto err_free_master;\r
+ }\r
+\r
+ master->mode_bits = SPI_CPOL | SPI_CPHA;\r
+ master->bus_num = pdev->id;\r
+ master->num_chipselect = pdata->num_chipselect;\r
+ master->dev.platform_data = pdata;\r
+ master->cleanup = rk29xx_spi_cleanup;\r
+ master->setup = rk29xx_spi_setup;\r
+ #if defined(QUICK_TRANSFER)\r
+ master->transfer = rk29xx_spi_quick_transfer;\r
+ #else\r
+ master->transfer = rk29xx_spi_transfer;\r
+ #endif\r
+ \r
+ dws->pdev = pdev;\r
+ /* Basic HW init */\r
+ spi_hw_init(dws);\r
+ /* Initial and start queue */\r
+ ret = init_queue(dws);\r
+ if (ret) {\r
+ dev_err(&master->dev, "problem initializing queue\n");\r
+ goto err_diable_hw;\r
+ }\r
+\r
+ ret = start_queue(dws);\r
+ if (ret) {\r
+ dev_err(&master->dev, "problem starting queue\n");\r
+ goto err_diable_hw;\r
+ }\r
+\r
+ spi_master_set_devdata(master, dws);\r
+ ret = spi_register_master(master);\r
+ if (ret) {\r
+ dev_err(&master->dev, "problem registering spi master\n");\r
+ goto err_queue_alloc;\r
+ }\r
+\r
+ ret =rk29xx_spim_cpufreq_register(dws);\r
+ if (ret < 0) {\r
+ printk(KERN_ERR"rk29xx spim failed to init cpufreq support\n");\r
+ goto err_queue_alloc;\r
+ }\r
+ DBG(KERN_INFO "rk29xx_spim: driver initialized\n");\r
+ mrst_spi_debugfs_init(dws);\r
+ return 0;\r
+\r
+err_queue_alloc:\r
+ destroy_queue(dws);\r
+err_diable_hw:\r
+ spi_enable_chip(dws, 0);\r
+ free_irq(dws->irq, dws);\r
+err_free_master:\r
+ spi_master_put(master);\r
+ iounmap(dws->regs);\r
+exit:\r
+ return ret;\r
+}\r
+\r
+static void __exit rk29xx_spim_remove(struct platform_device *pdev)\r
+{\r
+ struct spi_master *master = platform_get_drvdata(pdev);\r
+ struct rk29xx_spi *dws = spi_master_get_devdata(master);\r
+ int status = 0;\r
+\r
+ if (!dws)\r
+ return;\r
+ rk29xx_spim_cpufreq_deregister(dws);\r
+ mrst_spi_debugfs_remove(dws);\r
+\r
+ /* Remove the queue */\r
+ status = destroy_queue(dws);\r
+ if (status != 0)\r
+ dev_err(&dws->master->dev, "rk29xx_spi_remove: workqueue will not "\r
+ "complete, message memory not freed\n");\r
+ clk_put(dws->clock_spim);\r
+ clk_disable(dws->clock_spim);\r
+ spi_enable_chip(dws, 0);\r
+ /* Disable clk */\r
+ spi_set_clk(dws, 0);\r
+ free_irq(dws->irq, dws);\r
+\r
+ /* Disconnect from the SPI framework */\r
+ spi_unregister_master(dws->master);\r
+ iounmap(dws->regs);\r
+}\r
+\r
+\r
+#ifdef CONFIG_PM\r
+\r
+static int rk29xx_spim_suspend(struct platform_device *pdev, pm_message_t mesg)\r
+{\r
+ struct spi_master *master = platform_get_drvdata(pdev);\r
+ struct rk29xx_spi *dws = spi_master_get_devdata(master);\r
+ struct rk29xx_spi_platform_data *pdata = pdev->dev.platform_data;\r
+ int status;\r
+\r
+ status = stop_queue(dws);\r
+ if (status != 0)\r
+ return status;\r
+ clk_disable(dws->clock_spim);\r
+ if (pdata && pdata->io_fix_leakage_bug)\r
+ {\r
+ pdata->io_fix_leakage_bug( );\r
+ }\r
+ return 0;\r
+}\r
+\r
+static int rk29xx_spim_resume(struct platform_device *pdev)\r
+{\r
+ struct spi_master *master = platform_get_drvdata(pdev);\r
+ struct rk29xx_spi *dws = spi_master_get_devdata(master);\r
+ struct rk29xx_spi_platform_data *pdata = pdev->dev.platform_data;\r
+ int ret;\r
+ \r
+ clk_enable(dws->clock_spim); \r
+ spi_hw_init(dws);\r
+ ret = start_queue(dws);\r
+ if (ret)\r
+ dev_err(&dws->master->dev, "fail to start queue (%d)\n", ret);\r
+ if (pdata && pdata->io_resume_leakage_bug)\r
+ {\r
+ pdata->io_resume_leakage_bug( ); \r
+ }\r
+ return ret;\r
+}\r
+\r
+#else\r
+#define rk29xx_spim_suspend NULL\r
+#define rk29xx_spim_resume NULL\r
+#endif\r
+\r
+static struct platform_driver rk29xx_platform_spim_driver = {\r
+ .remove = __exit_p(rk29xx_spim_remove),\r
+ .driver = {\r
+ .name = "rk29xx_spim",\r
+ .owner = THIS_MODULE,\r
+ },\r
+ .suspend = rk29xx_spim_suspend,\r
+ .resume = rk29xx_spim_resume,\r
+};\r
+\r
+static int __init rk29xx_spim_init(void)\r
+{\r
+ int ret;\r
+ ret = platform_driver_probe(&rk29xx_platform_spim_driver, rk29xx_spim_probe); \r
+ return ret;\r
+}\r
+\r
+static void __exit rk29xx_spim_exit(void)\r
+{\r
+ platform_driver_unregister(&rk29xx_platform_spim_driver);\r
+}\r
+\r
+subsys_initcall(rk29xx_spim_init);\r
+module_exit(rk29xx_spim_exit);\r
+\r
+MODULE_AUTHOR("cmc cmc@rock-chips.com");\r
+MODULE_DESCRIPTION("Rockchip RK29xx spim port driver");\r
+MODULE_LICENSE("GPL");;\r
+\r