Brian G Rhodes <[email protected]> writes:

>  drivers/spi/spi_davinci.c |  852 
> +++++++++++++++++++++++++++++++++++++++++++++
>  1 files changed, 852 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/spi/spi_davinci.c
>

scripts/checkpatch.pl reports:

total: 4 errors, 21 warnings, 852 lines checked

Please fix these problems, and repost with a more verbose
description.

Kevin

> diff --git a/drivers/spi/spi_davinci.c b/drivers/spi/spi_davinci.c
> new file mode 100644
> index 0000000..63c3b14
> --- /dev/null
> +++ b/drivers/spi/spi_davinci.c
> @@ -0,0 +1,852 @@
> +/*
> + * drivers/spi/spi_davinci.c
> + *
> + * Copyright (C) Advanced Communication Design
> + *
> + * Based on code from spi_bfin5xx.c and atmel_spi.c
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/init.h>
> +#include <linux/clk.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/delay.h>
> +#include <linux/err.h>
> +#include <linux/interrupt.h>
> +#include <linux/spi/spi.h>
> +#include <linux/sched.h>
> +#include <linux/workqueue.h>
> +#include <linux/device.h>
> +
> +#include <asm/arch/clock.h>
> +#include <asm/arch/gpio.h>
> +#include <asm/arch/hardware.h>
> +#include <asm/arch/io.h>
> +#include <asm/arch/mux.h>
> +
> +#define START_STATE  ((void *)0)
> +#define RUNNING_STATE        ((void *)1)
> +#define DONE_STATE   ((void *)2)
> +#define ERROR_STATE  ((void *)-1)
> +
> +#define QUEUE_RUNNING        0
> +#define QUEUE_STOPPED        1
> +
> +#ifdef DEBUG
> +#define spew_debug printk
> +#else
> +#define spew_debug(...)
> +#endif
> +
> +struct davinci_spi {
> +     struct platform_device *pdev;
> +     struct spi_master *master;
> +     void __iomem *regs_base;
> +     int irq;
> +     u16 *pin_req;
> +     struct clk *clk;
> +
> +     struct workqueue_struct *workqueue;
> +     struct work_struct pump_messages;
> +     spinlock_t lock;
> +     struct list_head queue;
> +     int busy;
> +     int run;
> +
> +     struct tasklet_struct pump_transfers;
> +
> +     struct spi_message *cur_msg;
> +     struct spi_transfer *cur_transfer;
> +     size_t len_in_bytes;
> +     size_t len;
> +     void *tx;
> +     void *tx_end;
> +     void *rx;
> +     void *rx_end;
> +
> +     void (*wr) (struct davinci_spi *);
> +     void (*rd) (struct davinci_spi *);
> +     void (*duplex) (struct davinci_spi *);
> +};
> +
> +
> +/* SPI Register Addresses */
> +#define SPIGCR0     (DAVINCI_SPI_BASE)               /** SPI General Control 
> Register 0 */
> +#define SPIGCR1     (DAVINCI_SPI_BASE + 0x04)        /** SPI General Control 
> Register 1 */
> +#define SPIINT      (DAVINCI_SPI_BASE + 0x08)        /** SPI Interrupt 
> Register */
> +#define SPILVL      (DAVINCI_SPI_BASE + 0x0c)        /** SPI Pin Level 
> Register */
> +#define SPIFLG      (DAVINCI_SPI_BASE + 0x10)        /** SPI Flag Status 
> Register */
> +#define SPIPC0      (DAVINCI_SPI_BASE + 0x14)        /** SPI Pin Control 
> Register 0 */
> +#define SPIPC2      (DAVINCI_SPI_BASE + 0x1c)        /** SPI Pin Control 
> Register 2 */
> +#define SPIDAT1     (DAVINCI_SPI_BASE + 0x3c)        /** SPI Shift Register 
> 1 */
> +#define SPIBUF      (DAVINCI_SPI_BASE + 0x40)        /** SPI Buffer Register 
> */
> +#define SPIEMU      (DAVINCI_SPI_BASE + 0x44)        /** SPI Emulation 
> Register */
> +#define SPIDELAY    (DAVINCI_SPI_BASE + 0x48)        /** SPI Delay Register 
> */
> +#define SPIDEF      (DAVINCI_SPI_BASE + 0x4c)        /** SPI Default Chip 
> Select Register */
> +#define SPIFMT0     (DAVINCI_SPI_BASE + 0x50)        /** SPI Data Format 
> Register 0 */
> +#define SPIFMT1     (DAVINCI_SPI_BASE + 0x54)        /** SPI Data Format 
> Register 1 */
> +#define SPIFMT2     (DAVINCI_SPI_BASE + 0x58)        /** SPI Data Format 
> Register 2 */
> +#define SPIFMT3     (DAVINCI_SPI_BASE + 0x5c)        /** SPI Data Format 
> Register 3 */
> +#define INTVEC0     (DAVINCI_SPI_BASE + 0x60)        /** SPI Interrupt 
> Vector Register 0 */
> +#define INTVEC1     (DAVINCI_SPI_BASE + 0x64)        /** SPI Interrupt 
> Vector Register 1 */
> +
> +/* SPI Register bit definitions */
> +#define SPIGCR0_RESET           (1 << 0)
> +
> +#define SPIGCR1_SPIEN           (1 << 24)
> +#define SPIGCR1_CLKMOD          (1 << 1)
> +#define SPIGCR1_MASTER          (1 << 0)
> +
> +#define SPIINT_DMAREQEN         (1 << 16)
> +#define SPIINT_RXINTEN          (1 << 8)
> +#define SPIINT_OVRNINTEN        (1 << 6)
> +#define SPIINT_BITERRENA        (1 << 4)
> +
> +#define SPIFMTX_POLARITY        (1 << 17)
> +#define SPIFMTX_PHASE           (1 << 16)
> +#define SPIFMTX_PRESCALE_VAL    (7 << 8)
> +
> +#define SPIFLG_RXINTFLG         (1 << 8)
> +#define SPIFLG_OVRNINTFLG       (1 << 6)
> +#define SPIFLG_BITERRFLG        (1 << 4)
> +
> +#define SPIPC0_DIFUN            (1 << 11)
> +#define SPIPC0_DOFUN            (1 << 10)
> +#define SPIPC0_CLKFUN           (1 << 9)
> +#define SPIPC0_EN1FUN           (1 << 1)
> +#define SPIPC0_EN0FUN           (1 << 0)
> +
> +#define SPIDAT1_CSHOLD          (1 << 28)
> +#define SPIDAT1_CSNR1           (1 << 16)
> +#define SPIDAT1_CSNR0           (2 << 16)
> +
> +#define SPIDELAY_C2TDELAY_VAL   (6 << 24)
> +#define SPIDELAY_T2CDELAY_VAL   (3 << 16)
> +
> +#define SPIDEF_EN1DEF           (1 << 1)
> +#define SPIDEF_EN0DEF           (1 << 0)
> +
> +#define MODEBITS (SPI_CPOL | SPI_CPHA)
> +
> +static void u16_duplex(struct davinci_spi *dvspi)
> +{
> +     unsigned short status;
> +     
> +     while (dvspi->tx < dvspi->tx_end) {
> +             davinci_writel(SPIDAT1_CSHOLD | SPIDAT1_CSNR0 |
> +                            (*(u16 *) (dvspi->tx)), SPIDAT1);
> +             spew_debug("u16_duplex: wr=%x\n", *(u16 *) (dvspi->tx));
> +             do {
> +                     status = davinci_readw(SPIFLG);
> +                     if (status & SPIFLG_RXINTFLG)
> +                             break;
> +                     cpu_relax();
> +             } while (1);
> +             *(u16 *) (dvspi->rx) = davinci_readw(SPIBUF);
> +             spew_debug("u16_duplex: rd=%x\n", *(u16 *) (dvspi->rx));
> +             dvspi->rx += 2;
> +             dvspi->tx += 2;
> +     }
> +}
> +
> +
> +static void u16_write(struct davinci_spi *dvspi)
> +{
> +     while (dvspi->tx < dvspi->tx_end) {
> +             davinci_writel(SPIDAT1_CSHOLD | SPIDAT1_CSNR0 |
> +                            (*(u16 *) (dvspi->tx)), SPIDAT1);
> +             spew_debug("u16_write: wr=%x\n", *(u16 *) (dvspi->tx));
> +             dvspi->tx += 2;
> +     }
> +}
> +
> +
> +static void u16_read(struct davinci_spi *dvspi)
> +{
> +     unsigned short status;
> +     
> +     while (dvspi->rx < dvspi->rx_end) {
> +             do {
> +                     status = davinci_readw(SPIFLG);
> +                     if (status & SPIFLG_RXINTFLG)
> +                             break;
> +                     cpu_relax();
> +             } while (1);
> +             *(u16 *) (dvspi->rx) = davinci_readw(SPIBUF);
> +             spew_debug("u16_read: rd=%x\n", *(u16 *) (dvspi->rx));
> +             dvspi->rx += 2;
> +     }
> +}
> +
> +
> +/***************************************************
> + * spi_davinci_giveback                            *
> + *-------------------------------------------------*
> + *  Message transfer completed.  Queue next message
> + *  and run message's complete function if set.
> + ***************************************************/
> +
> +static void spi_davinci_giveback(struct davinci_spi *dvspi)
> +{
> +     struct spi_transfer *last_transfer;
> +     unsigned long flags;
> +     struct spi_message *message;
> +
> +     spew_debug("spi_davinci_giveback: m=%p, t=%p\n",
> +                dvspi->cur_msg, dvspi->cur_transfer);
> +
> +     spin_lock_irqsave(&dvspi->lock, flags);
> +     message = dvspi->cur_msg;
> +     dvspi->cur_msg = NULL;
> +     dvspi->cur_transfer = NULL;
> +     queue_work(dvspi->workqueue, &dvspi->pump_messages);
> +     spin_unlock_irqrestore(&dvspi->lock, flags);
> +
> +     last_transfer = list_entry(message->transfers.prev,
> +                                struct spi_transfer, transfer_list);
> +     message->state = NULL;
> +
> +     if (message->complete) {
> +             spew_debug("spi_davinci_giveback: message complete\n");
> +             message->complete(message->context);
> +     }
> +}
> +
> +
> +/***************************************************
> + * spi_davinci_next_transfer                       *
> + *-------------------------------------------------*
> + *  Update current transfer in message transfer
> + *  list.
> + ***************************************************/
> +
> +static void *spi_davinci_next_transfer(struct davinci_spi *dvspi)
> +{
> +     struct spi_message *message;
> +     struct spi_transfer *transfer;
> +
> +     spew_debug("spi_davinci_next_transfer: m=%p, t=%p\n",
> +                dvspi->cur_msg, dvspi->cur_transfer);
> +
> +     message = dvspi->cur_msg;
> +     transfer = dvspi->cur_transfer;
> +
> +     spew_debug
> +         ("spi_davinci_next_transfer: list.next=%p, message->transfers=%p\n",
> +          transfer->transfer_list.next, &message->transfers);
> +
> +     if (transfer->transfer_list.next != &message->transfers) {
> +             dvspi->cur_transfer =
> +                 list_entry(transfer->transfer_list.next,
> +                            struct spi_transfer, transfer_list);
> +             return RUNNING_STATE;
> +     }
> +
> +     return DONE_STATE;
> +}
> +
> +
> +/***************************************************
> + * spi_davinci_pump_transfers                      *
> + *-------------------------------------------------*
> + *  Send data over SPI bus for a single message
> + *  transfer.
> + ***************************************************/
> +
> +static void spi_davinci_pump_transfers(unsigned long data)
> +{
> +     struct davinci_spi *dvspi = (struct davinci_spi *) data;
> +     struct spi_message *message = NULL;
> +     struct spi_transfer *transfer = NULL;
> +     struct spi_transfer *previous = NULL;
> +     int transfer_success = 1;
> +     unsigned long flags;
> +
> +     spew_debug("spi_davinci_pump_transfers, m=%p, t=%p\n",
> +                dvspi->cur_msg, dvspi->cur_transfer);
> +
> +     spin_lock_irqsave(&dvspi->lock, flags);
> +
> +     message = dvspi->cur_msg;
> +     transfer = dvspi->cur_transfer;
> +
> +     spin_unlock_irqrestore(&dvspi->lock, flags);
> +
> +     /* handle abort */
> +     if (message->state == ERROR_STATE) {
> +             spew_debug("spi_davinci_pump_transfers: ERROR STATE\n");
> +             message->status = -EIO;
> +             spi_davinci_giveback(dvspi);
> +             return;
> +     }
> +
> +     /* handle end of message */
> +     if (message->state == DONE_STATE) {
> +             spew_debug("spi_davinci_pump_transfers: DONE STATE\n");
> +             message->status = 0;
> +             spi_davinci_giveback(dvspi);
> +             return;
> +     }
> +
> +     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);
> +             }
> +     }
> +
> +     spin_lock_irqsave(&dvspi->lock, flags);
> +     if (transfer->tx_buf != NULL) {
> +             dvspi->tx = (void *) transfer->tx_buf;
> +             dvspi->tx_end = dvspi->tx + transfer->len;
> +     } else {
> +             dvspi->tx = NULL;
> +     }
> +
> +     if (transfer->tx_buf != NULL) {
> +             dvspi->rx = transfer->rx_buf;
> +             dvspi->rx_end = dvspi->rx + transfer->len;
> +     } else {
> +             dvspi->rx = NULL;
> +     }
> +
> +     //  configure for 16byte messages
> +     dvspi->len = transfer->len >> 1;
> +
> +     dvspi->len_in_bytes = transfer->len;
> +
> +     message->state = RUNNING_STATE;
> +
> +     /* Write  -  then  -  Read */
> +
> +     if (dvspi->tx != NULL && dvspi->rx != NULL) {
> +             if (dvspi->duplex) {
> +                     dvspi->duplex(dvspi);
> +             }
> +
> +             if (dvspi->tx != dvspi->tx_end) {
> +                     transfer_success = 0;
> +             }
> +     } else if (dvspi->tx != NULL) {
> +             if (dvspi->wr) {
> +                     dvspi->wr(dvspi);
> +             }
> +
> +             if (dvspi->tx != dvspi->tx_end) {
> +                     transfer_success = 0;
> +             }
> +     } else if (dvspi->rx != NULL) {
> +             if (dvspi->rd) {
> +                     dvspi->rd(dvspi);
> +             }
> +
> +             if (dvspi->rx != dvspi->rx_end) {
> +                     transfer_success = 0;
> +             }
> +     }
> +
> +     spew_debug("spi_davinci_pump_transfers: success=%d\n",
> +                transfer_success);
> +
> +     if (!(transfer_success)) {
> +             message->state = ERROR_STATE;
> +     } else {
> +             message->actual_length += dvspi->len;
> +             message->state = spi_davinci_next_transfer(dvspi);
> +     }
> +
> +     tasklet_schedule(&dvspi->pump_transfers);
> +     spin_unlock_irqrestore(&dvspi->lock, flags);
> +}
> +
> +
> +/***************************************************
> + * spi_davinci_pump_messages                       *
> + *-------------------------------------------------*
> + *  Send a message.  Schedules transfer tasklet
> + *  which kickstarts sending a messages transfer
> + *  list.
> + ***************************************************/
> +
> +static void spi_davinci_pump_messages(struct work_struct *work)
> +{
> +     struct davinci_spi *dvspi;
> +     unsigned long flags;
> +
> +     dvspi = container_of(work, struct davinci_spi, pump_messages);
> +
> +     spew_debug("spi_davinci_pump_messages: m=%p, t=%p\n",
> +                dvspi->cur_msg, dvspi->cur_transfer);
> +
> +     spin_lock_irqsave(&dvspi->lock, flags);
> +
> +     spew_debug("spi_davinci_pump_messages: list empty=%d\n",
> +                list_empty(&dvspi->queue));
> +
> +     if (list_empty(&dvspi->queue) || dvspi->run == QUEUE_STOPPED) {
> +             dvspi->busy = 0;
> +             spin_unlock_irqrestore(&dvspi->lock, flags);
> +             return;
> +     }
> +
> +     if (dvspi->cur_msg) {
> +             spin_unlock_irqrestore(&dvspi->lock, flags);
> +             return;
> +     }
> +
> +     dvspi->cur_msg = list_entry(dvspi->queue.next,
> +                                 struct spi_message, queue);
> +     list_del_init(&dvspi->cur_msg->queue);
> +
> +     spew_debug("spi_davinci_pump_messages: mq=%p, qn=%p\n",
> +                &dvspi->queue.next, &dvspi->cur_msg->queue);
> +
> +     davinci_writeb(0, SPIDAT1 + 3);
> +
> +     dvspi->cur_msg->state = START_STATE;
> +
> +     dvspi->cur_transfer = list_entry(dvspi->cur_msg->transfers.next,
> +                                      struct spi_transfer,
> +                                      transfer_list);
> +
> +     tasklet_schedule(&dvspi->pump_transfers);
> +     dvspi->busy = 1;
> +     spin_unlock_irqrestore(&dvspi->lock, flags);
> +}
> +
> +
> +/***************************************************
> + * spi_davinci_intr                                *
> + *-------------------------------------------------*
> + *  Interrupt handler is only used to update the
> + *  length of the message being transmitted.
> + ***************************************************/
> +
> +static irqreturn_t spi_davinci_intr(int irq, void *dev_id)
> +{
> +     struct davinci_spi *dvspi = (struct davinci_spi *) dev_id;
> +     unsigned short status;
> +     struct spi_message *message = NULL;
> +
> +     spew_debug("spi_davinci_intr\n");
> +
> +     spin_lock(&dvspi->lock);
> +
> +     status = davinci_readw(SPIFLG);
> +     davinci_writew(status, SPIFLG);
> +
> +     message = dvspi->cur_msg;
> +
> +     spin_unlock(&dvspi->lock);
> +
> +     if (status & SPIFLG_RXINTFLG) {
> +             if (message) {
> +                     message->actual_length += dvspi->len_in_bytes;
> +             }
> +             return IRQ_HANDLED;
> +     }
> +
> +     return IRQ_NONE;
> +}
> +
> +
> +/***************************************************
> + * spi_davinci_setup                               *
> + *-------------------------------------------------*
> + *  Configure the chip select on the davinci and
> + *  setup the transfer function pointers for davinci.
> + ***************************************************/
> +
> +static int spi_davinci_setup(struct spi_device *spi)
> +{
> +     unsigned long csr;
> +     unsigned int bits = spi->bits_per_word;
> +     struct davinci_spi *dvspi = spi_master_get_devdata(spi->master);
> +
> +     if (spi->chip_select > spi->master->num_chipselect) {
> +             dev_err(&spi->dev,
> +                     "setup: invalid chipselect %u (%u defined)\n",
> +                     spi->chip_select, spi->master->num_chipselect);
> +             return -EINVAL;
> +     }
> +
> +     if (bits == 0) {
> +             bits = 8;
> +     }
> +
> +     if (bits < 8 || bits > 16) {
> +             dev_dbg(&spi->dev,
> +                     "setup: invalid bits_per_word %u\n", bits);
> +             return -EINVAL;
> +     }
> +
> +     if (spi->mode & ~MODEBITS) {
> +             dev_dbg(&spi->dev,
> +                     "setup: unsupported mode bits %x\n",
> +                     spi->mode & ~MODEBITS);
> +             return -EINVAL;
> +     }
> +
> +     /* disable SPI before changing params */
> +     davinci_writel(0, SPIGCR1);
> +
> +     csr = SPIFMTX_PRESCALE_VAL | bits;
> +     if (spi->mode & SPI_CPOL) {
> +             csr |= SPIFMTX_POLARITY;
> +     }
> +
> +     if (spi->mode & SPI_CPHA) {
> +             csr |= SPIFMTX_PHASE;
> +     }
> +
> +     dvspi->wr = u16_write;
> +     dvspi->rd = u16_read;
> +     dvspi->duplex = u16_duplex;
> +
> +     davinci_writel(csr, SPIFMT0 + (spi->chip_select * 4));
> +
> +     /* enable SPI, CLK and Master modes */
> +     davinci_writel(SPIGCR1_SPIEN | SPIGCR1_CLKMOD | SPIGCR1_MASTER,
> +                    SPIGCR1);
> +
> +     return 0;
> +}
> +
> +
> +/***************************************************
> + * spi_davinci_cleanup                             *
> + *-------------------------------------------------*
> + *
> + ***************************************************/
> +
> +static void spi_davinci_cleanup(struct spi_device *spi)
> +{
> +     return;
> +}
> +
> +
> +/***************************************************
> + * spi_davinci_transfer                            *
> + *-------------------------------------------------*
> + *  Append transfer to message queue and trigger
> + *  pump_messages.
> + ***************************************************/
> +
> +static int
> +spi_davinci_transfer(struct spi_device *spi, struct spi_message *msg)
> +{
> +     struct davinci_spi *dvspi = spi_master_get_devdata(spi->master);
> +     unsigned long flags;
> +
> +     spew_debug("spi_davinci_transfer: m=%p, t=%p\n",
> +                dvspi->cur_msg, dvspi->cur_transfer);
> +
> +     spin_lock_irqsave(&dvspi->lock, flags);
> +
> +     if (dvspi->run == QUEUE_STOPPED) {
> +             spin_unlock_irqrestore(&dvspi->lock, flags);
> +             return -ESHUTDOWN;
> +     }
> +
> +     msg->actual_length = 0;
> +     msg->status = -EINPROGRESS;
> +     msg->state = START_STATE;
> +
> +     spew_debug("spi_davinci_transfer: message=%p\n", msg);
> +
> +     list_add_tail(&msg->queue, &dvspi->queue);
> +
> +     if (dvspi->run == QUEUE_RUNNING) {
> +             queue_work(dvspi->workqueue, &dvspi->pump_messages);
> +     }
> +
> +     spin_unlock_irqrestore(&dvspi->lock, flags);
> +     return 0;
> +}
> +
> +
> +/***************************************************
> + * spi_davinci_init_queue                          *
> + *-------------------------------------------------*
> + *  Initialize work queue for message handling.
> + ***************************************************/
> +
> +static inline int spi_davinci_init_queue(struct davinci_spi *dvspi)
> +{
> +     INIT_LIST_HEAD(&dvspi->queue);
> +     spin_lock_init(&dvspi->lock);
> +
> +     dvspi->run = QUEUE_STOPPED;
> +     dvspi->busy = 0;
> +
> +     tasklet_init(&dvspi->pump_transfers, spi_davinci_pump_transfers,
> +                  (unsigned long) dvspi);
> +
> +     INIT_WORK(&dvspi->pump_messages, spi_davinci_pump_messages);
> +     dvspi->workqueue =
> +         create_singlethread_workqueue(dvspi->master->dev.parent->
> +                                       bus_id);
> +     if (!(dvspi->workqueue)) {
> +             return -EBUSY;
> +     }
> +
> +     return 0;
> +}
> +
> +
> +/***************************************************
> + * spi_davinci_start_queue                         *
> + *-------------------------------------------------*
> + *  Enable work queue.
> + ***************************************************/
> +
> +static inline int spi_davinci_start_queue(struct davinci_spi *dvspi)
> +{
> +     unsigned long flags;
> +
> +     spin_lock_irqsave(&dvspi->lock, flags);
> +
> +     if (dvspi->run == QUEUE_RUNNING || dvspi->busy) {
> +             spin_unlock_irqrestore(&dvspi->lock, flags);
> +             return -EBUSY;
> +     }
> +
> +     dvspi->run = QUEUE_RUNNING;
> +     dvspi->cur_msg = NULL;
> +     dvspi->cur_transfer = NULL;
> +
> +     spin_unlock_irqrestore(&dvspi->lock, flags);
> +
> +     queue_work(dvspi->workqueue, &dvspi->pump_messages);
> +
> +     return 0;
> +}
> +
> +
> +/***************************************************
> + * spi_davinci_probe                               *
> + *-------------------------------------------------*
> + *  Detect davinci SPI and configure davinci SPI
> + *  bus.
> + ***************************************************/
> +
> +static int __init spi_davinci_probe(struct platform_device *pdev)
> +{
> +     struct device *dev = &pdev->dev;
> +     struct spi_master *master;
> +     struct davinci_spi *dvspi;
> +     struct resource *res;
> +     int status = 0;
> +     int irq;
> +
> +     irq = platform_get_irq(pdev, 0);
> +     if (irq < 0) {
> +             dev_err(dev, "cannot get platform irq\n");
> +             return irq;
> +     }
> +
> +     master = spi_alloc_master(dev, sizeof(struct davinci_spi));
> +     if (!(master)) {
> +             dev_err(dev, "cannot alloc spi master\n");
> +             return -ENOMEM;
> +     }
> +
> +     dvspi = spi_master_get_devdata(master);
> +     dvspi->master = master;
> +     dvspi->pdev = pdev;
> +     dvspi->irq = irq;
> +     dvspi->clk = clk_get(&pdev->dev, "SPICLK");
> +
> +     if (!(dvspi->clk) || IS_ERR(dvspi->clk)) {
> +             spew_debug("spi_davinci_probe: bad clock\n");
> +     }
> +
> +     master->bus_num = pdev->id;
> +     master->num_chipselect = 2;
> +     master->cleanup = spi_davinci_cleanup;
> +     master->setup = spi_davinci_setup;
> +     master->transfer = spi_davinci_transfer;
> +
> +     status =
> +         request_irq(irq, spi_davinci_intr, 0, pdev->dev.bus_id, dvspi);
> +     if (status) {
> +             dev_err(dev, "cannot get interrupt\n");
> +             goto error_request_irq;
> +     }
> +
> +     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +     if (res == NULL) {
> +             dev_err(dev, "cannot get IORESOURCE_MEM\n");
> +             status = -ENOENT;
> +             goto error_get_resource;
> +     }
> +
> +     dvspi->regs_base =
> +         ioremap(res->start, (res->end - res->start + 1));
> +     if (dvspi->regs_base == NULL) {
> +             dev_err(dev, "cannot map io\n");
> +             status = -ENXIO;
> +             goto error_ioremap;
> +     }
> +
> +     status = spi_davinci_init_queue(dvspi);
> +     if (status != 0) {
> +             dev_err(dev, "cannot initialize queue\n");
> +             goto error_init_queue;
> +     }
> +
> +     /* configure GPIO pins for SPI */
> +     davinci_mux_peripheral(DAVINCI_MUX_SPI, 1);
> +     clk_enable(dvspi->clk);
> +     /* reset SPI */
> +     davinci_writel(0, SPIGCR0);
> +     mdelay(1);
> +     /* remove from reset */
> +     davinci_writel(SPIGCR0_RESET, SPIGCR0);
> +     /* enable pins: DI, DO, CLK, EN0 */
> +     davinci_writel(SPIPC0_DIFUN | SPIPC0_DOFUN | SPIPC0_CLKFUN |
> +                    SPIPC0_EN0FUN, SPIPC0);
> +     /* set hold time and setup time */
> +     davinci_writel(SPIDELAY_T2CDELAY_VAL | SPIDELAY_C2TDELAY_VAL,
> +                    SPIDELAY);
> +     /* set chip select for SPI_EN0 only */
> +     davinci_writel(SPIDAT1_CSNR0, SPIDAT1);
> +     /* errata says initialize twice */
> +     davinci_writel(SPIDAT1_CSNR0, SPIDAT1);
> +     /* SPI_EN0 and SPI_EN1 to 1 when idle */
> +     davinci_writel(SPIDEF_EN1DEF | SPIDEF_EN0DEF, SPIDEF);
> +     /* enable interrupts */
> +     davinci_writel(SPIINT_RXINTEN | SPIINT_OVRNINTEN |
> +                    SPIINT_BITERRENA, SPIINT);
> +
> +     status = spi_davinci_start_queue(dvspi);
> +     if (status != 0) {
> +             dev_err(dev, "cannot start queue\n");
> +             goto error_start_queue;
> +     }
> +
> +     platform_set_drvdata(pdev, dvspi);
> +     status = spi_register_master(master);
> +     if (status != 0) {
> +             dev_err(dev, "cannot register spi master\n");
> +             goto error_register_master;
> +     }
> +
> +     dev_info(&pdev->dev,
> +              "DaVinci SPI Controller at 0x%08lx (irq %d)\n",
> +              (unsigned long) res->start, irq);
> +     return 0;
> +
> +      error_register_master:
> +      error_start_queue:
> +      error_init_queue:
> +     free_irq(irq, master);
> +      error_ioremap:
> +     iounmap(dvspi->regs_base);
> +      error_get_resource:
> +      error_request_irq:
> +     clk_put(dvspi->clk);
> +     spi_master_put(master);
> +     return status;
> +}
> +
> +
> +/***************************************************
> + * spi_davinci_remove                              *
> + *-------------------------------------------------*
> + *  Shutdown davinci SPI bus.
> + ***************************************************/
> +
> +static int __exit spi_davinci_remove(struct platform_device *pdev)
> +{
> +     struct spi_master *master = platform_get_drvdata(pdev);
> +     struct davinci_spi *dvspi = spi_master_get_devdata(master);
> +     struct spi_message *msg;
> +
> +     dev_dbg(&pdev->dev, "spi_davinci_remove\n");
> +
> +     /* Terminate remaining queued transfers */
> +     list_for_each_entry(msg, &dvspi->queue, queue) {
> +             /* REVISIT unmapping the dma is a NOP on ARM and AVR32
> +              * but we shouldn't depend on that...
> +              */
> +             msg->status = -ESHUTDOWN;
> +             msg->complete(msg->context);
> +     }
> +
> +     /* Place SPI peripheral into reset */
> +     davinci_writel(0, SPIGCR0);
> +
> +     /* Remove the SPI output on the GPIO */
> +     davinci_mux_peripheral(DAVINCI_MUX_SPI, 0);
> +
> +     /* Disable the clock thus removing power from the peripheral */
> +     clk_disable(dvspi->clk);
> +     clk_put(dvspi->clk);
> +
> +     free_irq(dvspi->irq, master);
> +
> +     spi_unregister_master(master);
> +
> +     return 0;
> +}
> +
> +
> +#ifdef       CONFIG_PM
> +static int
> +spi_davinci_suspend(struct platform_device *pdev, pm_message_t mesg)
> +{
> +     struct spi_master *master = platform_get_drvdata(pdev);
> +     struct davinci_spi *dvspi = spi_master_get_devdata(master);
> +
> +     clk_disable(dvspi->clk);
> +     return 0;
> +}
> +
> +static int spi_davinci_resume(struct platform_device *pdev)
> +{
> +     struct spi_master *master = platform_get_drvdata(pdev);
> +     struct davinci_spi *dvspi = spi_master_get_devdata(master);
> +
> +     clk_enable(dvspi->clk);
> +     return 0;
> +}
> +
> +#else
> +#define      spi_davinci_suspend     NULL
> +#define      spi_davinci_resume      NULL
> +#endif
> +
> +static struct platform_driver spi_davinci_driver = {
> +     .driver = {
> +                .name = "spi_davinci",
> +                .owner = THIS_MODULE,
> +                },
> +     .suspend = spi_davinci_suspend,
> +     .resume = spi_davinci_resume,
> +     .remove = __exit_p(spi_davinci_remove),
> +};
> +
> +static int __init spi_davinci_init(void)
> +{
> +     return platform_driver_probe(&spi_davinci_driver,
> +                                  spi_davinci_probe);
> +}
> +
> +static void __exit spi_davinci_exit(void)
> +{
> +     platform_driver_unregister(&spi_davinci_driver);
> +}
> +
> +module_init(spi_davinci_init);
> +module_exit(spi_davinci_exit);
> +
> +MODULE_DESCRIPTION("DaVinci SPI Controller driver");
> +MODULE_AUTHOR("Brian Rhodes <[email protected]>");
> +MODULE_LICENSE("GPL");
>
> _______________________________________________
> Davinci-linux-open-source mailing list
> [email protected]
> http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source

_______________________________________________
Davinci-linux-open-source mailing list
[email protected]
http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source

Reply via email to