/* * 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 #include #include #include #include #include #include #include #include #include #include #include #include #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 #include 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>(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;icur_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;ipin_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"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:gsc3280-spi");