ckfwq/linux-3.0.4/drivers/spi/gsc3280_spi.c

1132 lines
31 KiB
C

/*
* GSC3280 SoC SPI controller driver
*
* Copyright (C) 2013 BLX IC Design Corp.,Ltd.
* Author: Davied, apple_guet@126.com
* Modify by: lufei, lufei@china-cpu.com
*
*/
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <linux/highmem.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>
#include <linux/spi/gsc3280_spi.h>
#include <linux/io.h>
#include <linux/scatterlist.h>
#include <gsc3280/gpio.h>
#include <asm/clock.h>
#include <gsc3280/gsc3280_regs.h>
#ifdef CONFIG_GSC3280_SPI_DEBUG
#define DBG(msg...) do { \
printk(KERN_INFO msg); \
} while (0)
#else
#define DBG(msg...) do { } while(0)
#endif
#define START_STATE ((void *)0)
#define RUNNING_STATE ((void *)1)
#define DONE_STATE ((void *)2)
#define ERROR_STATE ((void *)-1)
#define MRST_SPI_DEASSERT 0
#define MRST_SPI_ASSERT 1
#define GSC_SPI_ENABLE 0x01
#define GSC_SPI_DISABLE 0x00
/* Slave spi_dev related */
struct chip_data {
u8 n_bytes; /* current is a 1/2/4 byte op */
u8 cs_type; /* 0: chip cs, 1: gpio cs */
u8 cs_value; /* chip select value */
u8 lsb_flg; /* 1:LSB, 0: MSB */
u8 bits_per_word;
u16 cr;
u16 clk_div; /* baud rate divider, reg value */
u32 speed_hz; /* baud rate */
u32 pin_cs[3]; /* chip select pin */
u32 pin_cnt;
u8 poll_mode; /* 1 means use poll mode */
#ifdef CONFIG_GSC3280_SPI_DMA
u8 enable_dma;
u32 dma_width;
#endif
};
struct gsc3280_spi;
#ifdef CONFIG_GSC3280_SPI_DMA
//#include <linux/gsc_dmac.h>
#include <linux/gsc3280_dma.h>
struct gsc3280_spi_dma_ops {
int (*dma_init)(struct gsc3280_spi *gscs);
void (*dma_exit)(struct gsc3280_spi *gscs);
int (*dma_transfer)(struct gsc3280_spi *gscs, int cs_change);
};
#if 0
struct gsc3280_spi_dma_platform_data {
struct gsc3280_dma_slave dmas_tx;
struct gsc3280_dma_slave dmas_rx;
};
#endif
#endif
typedef enum {
GSC_SPI_QUEUE_STOP = 0x00,
GSC_SPI_QUEUE_RUN,
} spi_queue_state_e;
struct gsc3280_spi {
u8 n_bytes; //current is a 1 or 2 bytes op
u8 max_bits_per_word; //maxim is 16b
u8 bus_num;
u8 num_cs; //supported slave numbers
u8 busy;
int cs_change;
int irq;
u32 fifo_len; //depth of the FIFO buffer
u32 max_freq; //max bus freq supported
size_t len;
void *tx; //current tx point
void *tx_end;
void *rx; //current rx point
void *rx_end;
struct clk *clk;
spinlock_t slock;
void __iomem *regs;
struct list_head queue; //work queue
struct spi_master *master;
struct spi_message *cur_msg;
struct spi_transfer *cur_transfer;
struct chip_data *cur_chip;
struct chip_data *prev_chip;
struct workqueue_struct *workqueue; /* Driver message queue */
struct work_struct pump_messages;
spi_queue_state_e queue_state;
struct tasklet_struct pump_transfers; /* Message Transfer pump */
irqreturn_t (*transfer_handler)(struct gsc3280_spi *gscs);
#ifdef CONFIG_GSC3280_SPI_DMA
u32 dma_width;
int dma_mapped;
dma_addr_t rx_dma;
dma_addr_t tx_dma;
size_t rx_map_len;
size_t tx_map_len;
int dma_inited;
unsigned long paddr;
struct dma_chan *txchan;
struct scatterlist tx_sgl;
struct dma_chan *rxchan;
struct scatterlist rx_sgl;
int dma_chan_done;
struct device *dma_dev;
dma_addr_t dma_addr; /* phy address of the Data register */
struct gsc3280_spi_dma_ops *dma_ops;
void *dma_priv; /* platform relate info */
struct pci_dev *dmac;
#endif
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs;
#endif
};
static inline void gsc3280_spi_chip_sel(struct gsc3280_spi *gscs, u16 cs)
{
writel(cs, gscs->regs + GSC_SPI_CS);
}
/* Disable IRQ bits */
static inline void gsc3280_spi_mask_intr(struct gsc3280_spi *gscs, u32 mask)
{
u32 new_mask = 0;
if(gscs->irq == 14)
new_mask = readl(gscs->regs + GSC_SPI_ISR) | mask;
else
new_mask = readl(gscs->regs + GSC_SPI_IMSR) | mask;
writel(new_mask, gscs->regs + GSC_SPI_IMSR);
}
/* Enable IRQ bits */
static inline void gsc3280_spi_umask_intr(struct gsc3280_spi *gscs, u32 mask)
{
u32 new_mask = 0;
if(gscs->irq == 14)
new_mask = readl(gscs->regs + GSC_SPI_ISR) & ~mask;
else
new_mask = readl(gscs->regs + GSC_SPI_IMSR) & ~mask;
writel(new_mask, gscs->regs + GSC_SPI_IMSR);
}
static inline void gsc3280_enable_spi(struct gsc3280_spi *gscs, int enable)
{
u32 cr = 0;
if(enable)
cr = readl(gscs->regs + GSC_SPI_CTRL) | (GSC_SPI_CTL_EN);
else
cr = readl(gscs->regs + GSC_SPI_CTRL) & ~(GSC_SPI_CTL_EN);
writel(cr, gscs->regs + GSC_SPI_CTRL);
}
static inline void gsc3280_spi_clr_fifo(struct gsc3280_spi *gscs)
{
u32 cr = GSC_SPI_CTL_CLR;
cr |= readl(gscs->regs + GSC_SPI_CTRL);
writel(cr, gscs->regs + GSC_SPI_CTRL);
}
static void *gsc3280_spi_next_transfer(struct gsc3280_spi *gscs)
{
struct spi_message *msg = gscs->cur_msg;
struct spi_transfer *trans = gscs->cur_transfer;
if (trans->transfer_list.next != &msg->transfers) {
gscs->cur_transfer = list_entry(trans->transfer_list.next, struct spi_transfer, transfer_list);
return RUNNING_STATE;
} else
return DONE_STATE;
}
/* Caller already set message->status; dma and pio irqs are blocked */
static void gsc3280_spi_giveback(struct gsc3280_spi *gscs)
{
struct spi_message *msg;
unsigned long flags = 0;
int i;
int cs_type = gscs->cur_chip->cs_type;
int cs_value = gscs->cur_chip->cs_value;
int pin_cnt = gscs->cur_chip->pin_cnt;
int *pin_cs = gscs->cur_chip->pin_cs;
spin_lock_irqsave(&gscs->slock, flags);
msg = gscs->cur_msg;
gscs->cur_msg = NULL;
gscs->cur_transfer = NULL;
gscs->prev_chip = gscs->cur_chip;
gscs->cur_chip = NULL;
#ifdef CONFIG_GSC3280_SPI_DMA
gscs->dma_mapped = 0;
#endif
queue_work(gscs->workqueue, &gscs->pump_messages);
spin_unlock_irqrestore(&gscs->slock, flags);
DBG("gsc3280_spi_giveback\n");
if (cs_type == 0) //chip cs
writel(1, gscs->regs + GSC_SPI_CS);
else{ //io cs
for(i=0;i<pin_cnt;i++)
gpio_set_value(pin_cs[i],~((cs_value>>(i+1))&0x1));
}
msg->state = NULL;
if (msg->complete)
msg->complete(msg->context);
}
static void gsc3280_spi_xfer_done(struct gsc3280_spi *gscs)
{
/* Update total byte transferred return count actual bytes read */
gscs->cur_msg->actual_length += gscs->len;
/* Move to next transfer */
gscs->cur_msg->state = gsc3280_spi_next_transfer(gscs);
if (gscs->cur_msg->state == DONE_STATE) {
/* Handle end of message */
gscs->cur_msg->status = 0;
gsc3280_spi_giveback(gscs);
} else {
tasklet_schedule(&gscs->pump_transfers);
}
}
#ifdef CONFIG_GSC3280_SPI_DMA
#if 0
static struct gsc3280_spi_dma_platform_data spi_platform_data = {
.dmas_tx.dma_dev = &(gsc3280_dmac_device.dev),
.dmas_rx.dma_dev = &(gsc3280_dmac_device.dev),
};
#endif
/* Note: first step is the protocol driver prepares a dma-capable memory, and this func just need translate
the virt addr to physical */
static int map_dma_buffers(struct gsc3280_spi *gscs)
{
if (!gscs->cur_msg->is_dma_mapped || !gscs->dma_inited || !gscs->cur_chip->enable_dma
|| !gscs->dma_ops) {
return 0;
}
if (gscs->cur_transfer->tx_dma)
gscs->tx_dma = gscs->cur_transfer->tx_dma;
if (gscs->cur_transfer->rx_dma)
gscs->rx_dma = gscs->cur_transfer->rx_dma;
return 1;
}
static bool gsc3280_spi_dma_chan_filter(struct dma_chan *chan, void *param)
{
struct gsc3280_dma_slave *gscs = param;
return (gscs->dma_dev == chan->device->dev);
}
static int gscs_dma_init(struct gsc3280_spi *gscs)
{
struct gsc3280_spi_dma_platform_data *hsd = gscs->dma_priv;
//struct gsc_dma_slave *rxs, *txs;
struct gsc3280_dma_slave *rxs, *txs;
dma_cap_mask_t mask;
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
/* 1. Init rx channel */
rxs = &hsd->dmas_rx;
rxs->rx_reg = gscs->dma_addr;
rxs->reg_width = 0;
rxs->cfg_hi = 0x584;
rxs->cfg_lo = 0x640;
rxs->dst_msize = 0;
rxs->src_msize = 0;
rxs->dst_master = 1;
rxs->src_master = 0;
rxs->fc = 2;
gscs->rxchan = dma_request_channel(mask, gsc3280_spi_dma_chan_filter, rxs);
if (!gscs->rxchan)
goto err_exit;
gscs->rxchan->private = rxs;
/* 2. Init tx channel */
txs = &hsd->dmas_tx;
txs->tx_reg = gscs->dma_addr;
txs->reg_width = 0;
txs->cfg_hi = 0x5004;
txs->cfg_lo = 0xa20;
txs->src_msize = 0;
txs->dst_msize = 0;
txs->dst_master = 0;
txs->src_master = 1;
txs->fc = 1;
gscs->txchan = dma_request_channel(mask, gsc3280_spi_dma_chan_filter, txs);
if (!gscs->txchan)
goto free_rxchan;
gscs->txchan->private = txs;
gscs->dma_inited = 1;
return 0;
free_rxchan:
gsc3280_dma_single_free(gscs->rxchan);
err_exit:
return -1;
}
static void gscs_dma_exit(struct gsc3280_spi *gscs)
{
gsc3280_dma_single_free(gscs->txchan);
gsc3280_dma_single_free(gscs->rxchan);
}
static void gsc3280_spi_dma_done(void *arg)
{
struct gsc3280_spi *gscs = arg;
if (++gscs->dma_chan_done != 2)
return;
if (gscs->dma_mapped)
gscs->dma_ops->dma_exit(gscs);
gsc3280_spi_xfer_done(gscs);
}
static int gscs_dma_transfer(struct gsc3280_spi *gscs, int cs_change)
{
//struct he_cyclic_desc *txdesc = NULL,*rxdesc = NULL;
struct gsc3280_cyclic_desc *txdesc = NULL,*rxdesc = NULL;
struct dma_chan *txchan, *rxchan;
u16 dma_ctrl = 0;
/* 1. setup DMA related registers */
// if (cs_change) {
gsc3280_spi_chip_sel(gscs, 0x1);
// gsc3280_enable_spi(gscs, 0);
if (gscs->tx_dma)
dma_ctrl |= 1<<7;
if (gscs->rx_dma)
dma_ctrl |= 1<<6;
dma_ctrl |= readw(gscs->regs + GSC_SPI_CTRL);
writew(dma_ctrl, gscs->regs + GSC_SPI_CTRL);
// gsc3280_enable_spi(gscs, 1);
gsc3280_spi_chip_sel(gscs, 0x0);
// }
gscs->dma_chan_done = 0;
txchan = gscs->txchan;
rxchan = gscs->rxchan;
/* 2. Prepare the TX dma transfer */
//txdesc = gsc_dma_single_prep(txchan, gscs->tx_dma, gscs->len, DMA_TO_DEVICE);
txdesc = gsc3280_dma_single_prep(txchan, gscs->tx_dma, gscs->len, DMA_TO_DEVICE);
txdesc->period_callback = &gsc3280_spi_dma_done;
txdesc->period_callback_param = gscs;
/* 3. Prepare the RX dma transfer */
//rxdesc = gsc_dma_single_prep(rxchan, gscs->rx_dma, gscs->len, DMA_FROM_DEVICE);
rxdesc = gsc3280_dma_single_prep(rxchan, gscs->rx_dma, gscs->len, DMA_FROM_DEVICE);
rxdesc->period_callback = &gsc3280_spi_dma_done;
rxdesc->period_callback_param = gscs;
/* 4. submit */
/* rx must be started before tx due to spi instinct */
//gsc_dma_single_start(rxchan);
gsc3280_dma_single_start(rxchan);
//gsc_dma_single_start(txchan);
gsc3280_dma_single_start(txchan);
return 0;
}
static struct gsc3280_spi_dma_ops gscs_dma_ops = {
.dma_init = gscs_dma_init,
.dma_exit = gscs_dma_exit,
.dma_transfer = gscs_dma_transfer,
};
#endif
/* Return the max entries we should read out of rx fifo */
static inline u32 gsc3280_spi_rx_max(struct gsc3280_spi *gscs)
{
u32 rx_left = (gscs->rx_end - gscs->rx) / gscs->n_bytes;
return min(rx_left, (u32)readw(gscs->regs + GSC_SPI_RXFLR));
}
/* Return the max entries we can fill into tx fifo */
static inline u32 gsc3280_spi_tx_max(struct gsc3280_spi *gscs)
{
u32 tx_left,tx_room,rxtx_gap;
tx_left = (gscs->tx_end - gscs->tx) / gscs->n_bytes;
tx_room = gscs->fifo_len - readw(gscs->regs + GSC_SPI_TXFLR);
rxtx_gap = ((gscs->rx_end - gscs->rx) - (gscs->tx_end - gscs->tx))
/ gscs->n_bytes;
return min3(tx_left, tx_room,(u32)(gscs->fifo_len - rxtx_gap));
}
static void gsc3280_reader(struct gsc3280_spi *gscs)
{
u32 max = gsc3280_spi_rx_max(gscs);
u16 rxw;
while (max--) {
rxw = readl(gscs->regs + GSC_SPI_DA_S);
DBG("rxw = 0x%x\n\n", rxw);
/* Care rx only if the transfer's original "rx" is not null */
if (gscs->rx_end - gscs->len) {
if (gscs->n_bytes == 1)
*(u8 *)(gscs->rx) = rxw;
else
*(u16 *)(gscs->rx) = rxw;
}
gscs->rx += gscs->n_bytes;
}
}
static void gsc3280_writer(struct gsc3280_spi *gscs)
{
u32 max = gsc3280_spi_tx_max(gscs);
u16 txw = 0;
while (max--) {
/* Set the tx word if the transfer's original "tx" is not null */
if (gscs->tx_end - gscs->len) {
if (gscs->n_bytes == 1)
txw = *(u8 *)(gscs->tx);
else
txw = *(u16 *)(gscs->tx);
}
if(gscs->irq == 14)
udelay(1);
DBG("txw = 0x%x\n\n", txw);
writel(txw, gscs->regs + GSC_SPI_DA_S);
gscs->tx += gscs->n_bytes;
}
}
/* Must be called inside pump_transfers() */
static void gsc3280_spi_poll_transfer(struct gsc3280_spi *gscs)
{
do {
gsc3280_writer(gscs);
gsc3280_reader(gscs);
cpu_relax();
} while (gscs->rx_end > gscs->rx);
gsc3280_spi_xfer_done(gscs);
}
static void int_error_stop(struct gsc3280_spi *gscs, const char *msg)
{
/* Stop the hw */
gsc3280_enable_spi(gscs, GSC_SPI_DISABLE);
gsc3280_spi_clr_fifo(gscs);
dev_err(&gscs->master->dev, "%s\n", msg);
gscs->cur_msg->state = ERROR_STATE;
tasklet_schedule(&gscs->pump_transfers);
}
static irqreturn_t interrupt_transfer(struct gsc3280_spi *gscs)
{
u16 irq_status ;
if(gscs->irq == 14)
irq_status = readw(gscs->regs + GSC_SPI_IMSR);
else
irq_status = readw(gscs->regs + GSC_SPI_ISR);
/* Error handling */
if (irq_status & (SPI_INT_TX_H_OVER | SPI_INT_RX_L_OVER | SPI_INT_RX_H_OVER)){
printk(KERN_INFO "irq_status=0x%x\n",irq_status);
writew(0xe, gscs->regs + GSC_SPI_ISR);
int_error_stop(gscs, "interrupt_transfer: fifo overrun/underrun");
return IRQ_HANDLED;
}
gsc3280_reader(gscs);
if (gscs->rx_end == gscs->rx) {
gsc3280_spi_mask_intr(gscs, SPI_INT_TX_EMPTY);
gsc3280_spi_xfer_done(gscs);
return IRQ_HANDLED;
}
if (irq_status & SPI_INT_TX_EMPTY) {
gsc3280_spi_mask_intr(gscs, SPI_INT_TX_EMPTY);
gsc3280_writer(gscs);
/* Enable TX irq always, it will be disabled when RX finished */
gsc3280_spi_umask_intr(gscs, SPI_INT_TX_EMPTY);
}
return IRQ_HANDLED;
}
/* this is transfer message function */
static irqreturn_t gsc3280_spi_irq(int irq, void *dev_id)
{
struct gsc3280_spi *gscs = dev_id;
u16 irq_status;
if(irq == 14)
irq_status = readw(gscs->regs + GSC_SPI_IMSR);
else
irq_status = readw(gscs->regs + GSC_SPI_ISR);
if (!irq_status)
return IRQ_NONE;
if (!gscs->cur_msg) {
gsc3280_spi_mask_intr(gscs, SPI_INT_TX_EMPTY);
return IRQ_HANDLED;
}
return gscs->transfer_handler(gscs);
}
/* when call this function,the cur_msg is the new msg */
static void gsc3280_spi_pump_transfers(unsigned long data)
{
struct gsc3280_spi *gscs = (struct gsc3280_spi *)data;
int clk_div = 0;
u32 imask = 0, cr = 0;
struct spi_message *message = NULL;
struct spi_transfer *transfer = NULL;
struct spi_transfer *previous = NULL;
struct spi_device *spi = NULL;
struct chip_data *chip = NULL;
/* Get current state information */
message = gscs->cur_msg;
transfer = gscs->cur_transfer;
chip = gscs->cur_chip;
spi = message->spi;
DBG("gsc3280_spi_pump_transfers\n");
if (message->state == ERROR_STATE) {
DBG("!!!!pump_transfers:cur msg state error!\n");
message->status = -EIO;
goto early_exit;
}
/* Handle end of message */
if (message->state == DONE_STATE) {
message->status = 0;
goto early_exit;
}
/* Delay if requested at end of transfer*/
if (message->state == RUNNING_STATE) {
previous = list_entry(transfer->transfer_list.prev, struct spi_transfer, transfer_list);
if (previous->delay_usecs)
udelay(previous->delay_usecs);
}
#ifdef CONFIG_GSC3280_SPI_DMA
gscs->dma_width = chip->dma_width;
gscs->rx_dma = transfer->rx_dma;
gscs->tx_dma = transfer->tx_dma;
#endif
gscs->tx = (void *)transfer->tx_buf;
gscs->tx_end = gscs->tx + transfer->len;
gscs->rx = transfer->rx_buf;
gscs->rx_end = gscs->rx + transfer->len;
gscs->cs_change = transfer->cs_change;
gscs->len = transfer->len;
/* Handle per transfer options for bpw and speed */
if (transfer->speed_hz) {
if (transfer->speed_hz != chip->speed_hz) {
if (transfer->speed_hz > (gscs->max_freq/2)) {
printk(KERN_ERR "SPI: unsupported freq: %dHz\n", transfer->speed_hz);
message->status = -EIO;
return;
} else
chip->speed_hz = transfer->speed_hz;
}
clk_div = gscs->max_freq / chip->speed_hz;
if((gscs->max_freq%chip->speed_hz)>0)
clk_div +=1;
if(clk_div%2)
clk_div = clk_div/2;
else
clk_div = (clk_div/2) -1;
chip->clk_div = (u16)clk_div;
writel(chip->clk_div, gscs->regs + GSC_SPI_SEABAUR);
}
if (transfer->bits_per_word) {
switch (transfer->bits_per_word) {
case 8:
case 16:
gscs->n_bytes = transfer->bits_per_word >> 3;
#ifdef CONFIG_GSC3280_SPI_DMA
gscs->dma_width = gscs->n_bytes;
#endif
break;
default:
printk(KERN_ERR "SPI: unsupported bits:" "%db\n", transfer->bits_per_word);
message->status = -EIO;
return;
}
}
message->state = RUNNING_STATE;
/* Interrupt mode we only need set the TXEI IRQ, as TX/RX always happen syncronizely */
if (!chip->poll_mode) {
gscs->transfer_handler = interrupt_transfer;
imask |= SPI_INT_TX_H_OVER | SPI_INT_RX_L_OVER | SPI_INT_RX_H_OVER | SPI_INT_RX_FULL ;
if (gscs->tx != NULL) {
imask |= SPI_INT_TX_EMPTY;
}
gsc3280_spi_umask_intr(gscs, imask);
}
cr = chip->cr | GSC_SPI_CTL_EN;
writel(cr, gscs->regs + GSC_SPI_CTRL); /* enable spi */
#ifdef CONFIG_GSC3280_SPI_DMA
/* Check if current transfer is a DMA transaction */
gscs->dma_mapped = map_dma_buffers(gscs);
if (gscs->dma_mapped)
//gscs->dma_ops->dma_transfer(gscs, cs_change);
gscs->dma_ops->dma_transfer(gscs, gscs->cs_change);
#endif
if (chip->poll_mode)
gsc3280_spi_poll_transfer(gscs);
return;
early_exit:
gsc3280_spi_giveback(gscs);
return;
}
/*
* when call this function, no msg transfering
* deal one msg when call this funciton once.
*
*/
static void gsc3280_spi_pump_messages(struct work_struct *work)
{
unsigned long flags = 0;
int i;
struct gsc3280_spi *gscs = container_of(work, struct gsc3280_spi, pump_messages);
DBG("####gsc3280_spi_pump_messages####\n");
spin_lock_irqsave(&gscs->slock, flags);
if (list_empty(&gscs->queue) || (gscs->queue_state == GSC_SPI_QUEUE_STOP)) {
DBG("msg is finished!\n");
spin_unlock_irqrestore(&gscs->slock, flags);
gscs->busy = 0;
return;
}
/* Make sure we are not already running a message */
if (gscs->cur_msg) {
spin_unlock_irqrestore(&gscs->slock, flags);
return;
}
gscs->cur_msg = list_entry(gscs->queue.next, struct spi_message, queue);
if (!gscs->cur_msg) {
spin_unlock_irqrestore(&gscs->slock, flags);
DBG("!!!!gsc3280_spi_pump_messages: current no msg!\n");
return;
}
list_del_init(&gscs->cur_msg->queue);
gscs->cur_msg->state = START_STATE;
gscs->cur_chip = spi_get_ctldata(gscs->cur_msg->spi);
gscs->n_bytes = gscs->cur_chip->n_bytes;
if (gscs->cur_chip->cs_type == 0) //chip cs
writel(0, gscs->regs + GSC_SPI_CS);
else{ //io cs
writel(1, gscs->regs + GSC_SPI_CS);
for(i=0;i<gscs->cur_chip->pin_cnt;i++)
gpio_set_value(gscs->cur_chip->pin_cs[i],((gscs->cur_chip->cs_value>>(i+1))&0x1));
}
/* get first transfer */
gscs->cur_transfer = list_entry(gscs->cur_msg->transfers.next, struct spi_transfer, transfer_list);
if (!gscs->cur_transfer) {
DBG("!!!!gsc3280_spi_pump_transfers: current no transfer!\n");
return;
}
tasklet_schedule(&gscs->pump_transfers);
gscs->busy = 1;
spin_unlock_irqrestore(&gscs->slock, flags);
return;
}
/* spi driver call this function transfer data */
static int gsc3280_spi_transfer(struct spi_device *spi, struct spi_message *msg)
{
unsigned long flags = 0;
struct gsc3280_spi *gscs = spi_master_get_devdata(spi->master);
spin_lock_irqsave(&gscs->slock, flags);
if (gscs->queue_state == GSC_SPI_QUEUE_STOP) {
spin_unlock_irqrestore(&gscs->slock, flags);
return -ESHUTDOWN;
}
msg->actual_length = 0;
msg->status = -EINPROGRESS;
msg->state = START_STATE;
list_add_tail(&msg->queue, &gscs->queue);
if (gscs->queue_state == GSC_SPI_QUEUE_RUN && !gscs->busy) {
DBG("####gsc3280 spi transfer start####\n");
if (gscs->cur_transfer || gscs->cur_msg) {
queue_work(gscs->workqueue,
&gscs->pump_messages);
printk(KERN_CRIT "queue message\n");
}
else {
/* If no other data transaction in air, just go */
spin_unlock_irqrestore(&gscs->slock, flags);
gsc3280_spi_pump_messages(&gscs->pump_messages);
// printk(KERN_CRIT "transfer ok.\n");
return 0;
}
}
spin_unlock_irqrestore(&gscs->slock, flags);
DBG("####gsc3280 spi transfer success####\n");
return 0;
}
/* This may be called twice for each spi dev */
static int gsc3280_spi_setup(struct spi_device *spi)
{
int i,clk_div,ret = 0;
struct chip_data *chip = NULL;
struct gsc3280_spi_info *chip_info = NULL;
struct gsc3280_spi *gscs = spi_master_get_devdata(spi->master);
DBG("######gsc3280 spi bus setup start######\n");
chip = spi_get_ctldata(spi); /* Only alloc on first setup */
if (!chip) {
chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);
if (!chip) {
DBG("!!!!kzalloc error!\n");
ret = -ENOMEM;
goto exit;
}
}
chip_info = spi->controller_data;
/* chip_info doesn't always exist */
if (chip_info) {
#ifdef CONFIG_GSC3280_SPI_DMA
chip->enable_dma = chip_info->enable_dma;
#endif
chip->poll_mode = chip_info->poll_mode;
chip->cs_type = chip_info->cs_type;
chip->cs_value = chip_info->cs_value;
chip->bits_per_word = chip_info->bits_per_word;
chip->lsb_flg = chip_info->lsb_flg;
chip->pin_cnt = chip_info->pin_cnt;
//init cancel cs
if (chip->cs_type == 0) //chip cs
writel(1, gscs->regs + GSC_SPI_CS);
else{ //io cs
for(i=0;i<chip->pin_cnt;i++){
chip->pin_cs[i]=chip_info->pin_cs[i];
if(gpio_request(chip->pin_cs[i], spi->modalias)==0)
gpio_direction_output(chip->pin_cs[i],~((chip->cs_value>>(i+1))&0x1));
}
}
}
if (spi->bits_per_word == 8) {
chip->n_bytes = 1;
#ifdef CONFIG_GSC3280_SPI_DMA
chip->dma_width = 1;
#endif
} else if (spi->bits_per_word == 16) {
chip->n_bytes = 2;
#ifdef CONFIG_GSC3280_SPI_DMA
chip->dma_width = 2;
#endif
} else {
DBG("!!!!spi->bits_per_word = %d error!\n", spi->bits_per_word);
ret = -EINVAL;
goto exit;
}
if(spi->max_speed_hz > gscs->max_freq/2)
chip->speed_hz = gscs->max_freq/2;
else
chip->speed_hz = spi->max_speed_hz;
clk_div = gscs->max_freq / chip->speed_hz;
// if((gscs->max_freq%chip->speed_hz)>0)
// clk_div +=1;
if(clk_div%2)
clk_div = clk_div/2;
else
clk_div = (clk_div/2) -1;
writel(clk_div , gscs->regs + GSC_SPI_SEABAUR);
printk(KERN_INFO "SPI: max freq = %dHz\n", gscs->max_freq);
printk(KERN_INFO "SPI: max speed = %dHz\n", spi->max_speed_hz);
printk(KERN_INFO "SPI: rel speed = %dHz\n", gscs->max_freq/((clk_div+1)*2));
chip->cr = (chip->lsb_flg << GSC_SPI_CTL_LSB) | (spi->mode << GSC_SPI_CTL_MOD)
| ((chip->bits_per_word - 1) << GSC_SPI_CTL_DSS);
spi_set_ctldata(spi, chip);
exit:
if (ret != 0)
DBG("!!!!gsc3280 spi bus setup error!\n");
else
DBG("######gsc3280 spi bus setup success######\n");
return ret;
}
static void gsc3280_spi_cleanup(struct spi_device *spi)
{
struct chip_data *chip = spi_get_ctldata(spi);
kfree(chip);
}
static int __devinit gsc3280_init_queue(struct gsc3280_spi *gscs)
{
INIT_LIST_HEAD(&gscs->queue);
spin_lock_init(&gscs->slock);
gscs->queue_state = GSC_SPI_QUEUE_STOP;
gscs->busy = 0;
tasklet_init(&gscs->pump_transfers, gsc3280_spi_pump_transfers, (unsigned long)gscs);
INIT_WORK(&gscs->pump_messages, gsc3280_spi_pump_messages);
gscs->workqueue = create_singlethread_workqueue(dev_name(gscs->master->dev.parent));
if (gscs->workqueue == NULL) {
return -EBUSY;
}
return 0;
}
static int gsc3280_start_queue(struct gsc3280_spi *gscs)
{
unsigned long flags = 0;
spin_lock_irqsave(&gscs->slock, flags);
if ((gscs->queue_state == GSC_SPI_QUEUE_RUN) || gscs->busy) {
spin_unlock_irqrestore(&gscs->slock, flags);
return -EBUSY;
}
gscs->queue_state = GSC_SPI_QUEUE_RUN;
gscs->cur_msg = NULL;
gscs->cur_transfer = NULL;
gscs->cur_chip = NULL;
gscs->prev_chip = NULL;
spin_unlock_irqrestore(&gscs->slock, flags);
queue_work(gscs->workqueue, &gscs->pump_messages);
return 0;
}
static int gsc3280_spi_stop_queue(struct gsc3280_spi *gscs)
{
int ret = 0;
unsigned long flags;
unsigned limit = 50;
spin_lock_irqsave(&gscs->slock, flags);
while ((!list_empty(&gscs->queue) || gscs->busy) && limit--) {
spin_unlock_irqrestore(&gscs->slock, flags);
msleep(10);
spin_lock_irqsave(&gscs->slock, flags);
}
if (!list_empty(&gscs->queue) || gscs->busy)
ret = -EBUSY;
else
gscs->queue_state = GSC_SPI_QUEUE_STOP;
spin_unlock_irqrestore(&gscs->slock, flags);
return ret;
}
static int gsc3280_spi_destroy_queue(struct gsc3280_spi *gscs)
{
int ret = 0;
ret = gsc3280_spi_stop_queue(gscs);
if (ret != 0)
return ret;
destroy_workqueue(gscs->workqueue);
return ret;
}
/* Restart the controller, disable all interrupts, clean fifo */
static void gsc3280_spi_hw_init(struct gsc3280_spi *gscs)
{
gsc3280_enable_spi(gscs, GSC_SPI_DISABLE);
gsc3280_spi_mask_intr(gscs, GSC_SPI_SR_MASK);
if (!gscs->fifo_len) {
if(gscs->irq == 14) //spi0
gscs->fifo_len = 0x8;
else //spi1
gscs->fifo_len = 0x10;
}
writew(0x00, gscs->regs + GSC_SPI_TXFTLR);
writew(0x00, gscs->regs + GSC_SPI_RXFTLR);
gsc3280_spi_clr_fifo(gscs);
gsc3280_enable_spi(gscs, GSC_SPI_ENABLE);
}
static int __init gsc3280_spi_probe(struct platform_device *pdev)
{
int ret = 0;
struct gsc3280_spi *gscs;
struct spi_master *master;
struct resource *mem, *ioarea;
/*When used high speed SPI, then must reconfig the SPI clock */
/*SPI0 ReInit*/
__raw_writel(0x1,(__iomem void *)GSC3280_REGADDR_SYSCTL_CLKDIV_SPI0);
/*SPI1 ReInit*/
__raw_writel(0x1,(__iomem void *)GSC3280_REGADDR_SYSCTL_CLKDIV_SPI1);
DBG("############\n");
DBG("gsc3280 spi probe start\n");
master = spi_alloc_master(&pdev->dev, sizeof(struct gsc3280_spi));
if (!master) {
ret = -ENOMEM;
DBG("!!!!spi_alloc_master error\n");
goto exit;
}
gscs = spi_master_get_devdata(master);
memset(gscs, 0, sizeof(struct gsc3280_spi));
gscs->master = spi_master_get(master);
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem) {
DBG("!!!!no mem resource!\n");
ret = -EINVAL;
goto err_kfree;
}
ioarea = request_mem_region(mem->start, resource_size(mem), pdev->name);
if (!ioarea) {
DBG("!!!!SPI region already claimed!\n");
ret = -EBUSY;
goto err_kfree;
}
gscs->regs = ioremap_nocache(mem->start, resource_size(mem));
if (!gscs->regs) {
DBG("!!!!SPI ioremap error!\n");
ret = -ENOMEM;
goto err_release_reg;
}
DBG("gscs->regs = 0x%p\n", gscs->regs);
gscs->irq = platform_get_irq(pdev, 0);
if (gscs->irq < 0) {
DBG("!!!!no irq resource!\n");
ret = gscs->irq;
goto err_unmap;
}
ret = request_irq(gscs->irq, gsc3280_spi_irq, IRQF_DISABLED, dev_name(&pdev->dev), gscs);
if (ret < 0) {
DBG("!!!!can not get IRQ!\n");
goto err_irq;
}
gscs->clk = clk_get(NULL, pdev->dev.platform_data);
if (IS_ERR(gscs->clk)) {
DBG("!!!!failed to find spi1 clock source!\n");
ret = PTR_ERR(gscs->clk);
goto err_irq;
}
gscs->max_freq = clk_get_rate(gscs->clk);
clk_enable(gscs->clk);
gscs->bus_num = pdev->id;
gscs->num_cs = 4;
gscs->prev_chip = NULL;
#ifdef CONFIG_GSC3280_SPI_DMA
// gscs->dma_priv = pdev->dev.platform_data = &spi_platform_data;
gscs->dma_priv = pdev->dev.platform_data;
pdata = pdev->dev.platform_data;
if (!gscs->dma_priv)
goto err_clk;
gscs->dma_ops = &gscs_dma_ops;
gscs->dma_inited = 0;
gscs->dma_addr = (dma_addr_t)(gscs->regs + 0x24) & 0x1fffffff;
#endif
platform_set_drvdata(pdev, master);
master->mode_bits = SPI_CPOL | SPI_CPHA |SPI_CS_HIGH;
master->bus_num = gscs->bus_num;
master->num_chipselect = gscs->num_cs;
master->cleanup = gsc3280_spi_cleanup;
master->setup = gsc3280_spi_setup;
master->transfer = gsc3280_spi_transfer;
gsc3280_spi_hw_init(gscs);
#ifdef CONFIG_GSC3280_SPI_DMA
if (gscs->dma_ops && gscs->dma_ops->dma_init) {
ret = gscs->dma_ops->dma_init(gscs);
if (ret) {
dev_warn(&master->dev, "DMA init failed\n");
gscs->dma_inited = 0;
}
}
#endif
ret = gsc3280_init_queue(gscs);
if (ret != 0) {
DBG("!!!!problem initializing queue!\n");
goto err_diable_hw;
}
ret = gsc3280_start_queue(gscs);
if (ret != 0) {
DBG("!!!!problem starting queue!\n");
goto err_queue_alloc;
}
ret = spi_register_master(master);
if (ret != 0) {
DBG("!!!!register spi master error!\n");
goto err_queue_alloc;
}
DBG("gsc3280 spi probe success\n");
DBG("############\n");
return 0;
//err_free_master:
//spi_master_put(master);
err_queue_alloc:
gsc3280_spi_destroy_queue(gscs);
#ifdef CONFIG_GSC3280_SPI_DMA
if (gscs->dma_ops && gscs->dma_ops->dma_exit)
gscs->dma_ops->dma_exit(gscs);
#endif
err_diable_hw:
gsc3280_enable_spi(gscs, GSC_SPI_DISABLE);
err_clk:
clk_disable(gscs->clk);
clk_put(gscs->clk);
err_irq:
free_irq(gscs->irq, gscs);
err_unmap:
iounmap(gscs->regs);
err_release_reg:
release_mem_region(mem->start, resource_size(mem));
err_kfree:
kfree(gscs);
kfree(master);
exit:
printk(KERN_ERR "!!!!!!gsc3280 probe error!!!!!!\n");
return ret;
}
void __exit gsc3280_spi_remove(struct platform_device *pdev)
{
int ret = 0;
struct spi_master *master = platform_get_drvdata(pdev);
struct gsc3280_spi *gscs = spi_master_get_devdata(master);
if (!gscs)
return;
ret = gsc3280_spi_destroy_queue(gscs);
if (ret != 0)
dev_err(&gscs->master->dev, "gsc3280_spi_remove: workqueue will not "
"complete, message memory not freed\n");
#ifdef CONFIG_GSC3280_SPI_DMA
if (gscs->dma_ops && gscs->dma_ops->dma_exit)
gscs->dma_ops->dma_exit(gscs);
#endif
gsc3280_enable_spi(gscs, GSC_SPI_DISABLE);
free_irq(gscs->irq, gscs);
iounmap(gscs->regs);
clk_disable(gscs->clk);
clk_put(gscs->clk);
gscs->clk = NULL;
spi_unregister_master(gscs->master);
}
static int gsc3280_spi_suspend(struct platform_device *pdev, pm_message_t mesg)
{
int ret = 0;
struct spi_master *master = platform_get_drvdata(pdev);
struct gsc3280_spi *gscs = spi_master_get_devdata(master);
ret = gsc3280_spi_stop_queue(gscs);
if (ret != 0)
return ret;
gsc3280_enable_spi(gscs, GSC_SPI_DISABLE);
return ret;
}
static int gsc3280_spi_resume(struct platform_device *pdev)
{
int ret = 0;
struct spi_master *master = platform_get_drvdata(pdev);
struct gsc3280_spi *gscs = spi_master_get_devdata(master);
gsc3280_spi_hw_init(gscs);
ret = gsc3280_start_queue(gscs);
if (ret != 0)
dev_err(&gscs->master->dev, "fail to start queue (%d)\n", ret);
return ret;
}
static struct platform_driver gsc3280_spi_driver = {
.driver = {
.name = "gsc3280-spi",
.owner = THIS_MODULE,
},
.suspend = gsc3280_spi_suspend,
.resume = gsc3280_spi_resume,
.remove = __exit_p(gsc3280_spi_remove),
};
static int __init gsc3280_spi_init(void)
{
platform_driver_probe(&gsc3280_spi_driver, gsc3280_spi_probe);
return 0;
}
static void __exit gsc3280_spi_exit(void)
{
platform_driver_unregister(&gsc3280_spi_driver);
}
module_init(gsc3280_spi_init);
module_exit(gsc3280_spi_exit);
MODULE_DESCRIPTION("BLX GSC3280 SoC SPI Controller driver");
MODULE_AUTHOR("Davied<apple_guet@126.com>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:gsc3280-spi");