This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

SPI1 on dm368 issue

Hi all,

I am trying to use the spi1 port on my custom DM368 board, and I have porting a spi driver for it. the following is my spi driver demo( master, and use only SCLK, SIMO, SOMI three pins):
/*-----------------------driver code begin---------------------------------------------*/
 #include <linux/module.h>
#include <linux/version.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/gpio.h>
#include <mach/io.h>
#include <mach/cputype.h>
#include <mach/hardware.h>
#include <linux/clk.h>
#include <mach/dm365.h>
#include <mach/mux.h>


#define DEV_IRQ_NAME      "FPGA_SPI"
#define DEV_IRQ_ID      "FPGA_SPI"
#define MODULE_NAME      "davinci_spi"

///////////////////////////
// DEFINITIONS & GLOBALS
//////////////////////////
// Register definitions to control the SPI,refer to dm368 spi referrence guide.pdf & dm368 ARM subsystem.pdf
#define SPIGCR0            0x01C66800
#define SPIGCR1            0x01C66804
#define SPIINT                0x01C66808
#define SPILVL                0x01C6680C
#define SPIFLG                0x01C66810
// SPI Flag Status Register
#define SPIPC0                0x01C66814
// SPI Pin Control Register 0
#define SPIPC2                0x01C6681C
// SPI Pin Control Register 2
#define SPIDAT1            0x01C6683C
// SPI Shift Register 1
#define SPIBUF                0x01C66840
// SPI Buffer Register
#define SPIEMU                0x01C66844
// SPI Emulation Register
#define SPIDELAY            0x01C66848
// SPI Delay Register
#define SPIDEF                0x01C6684C
// SPI Default Chip Select Register
#define SPIFMT0            0x01C66850
// SPI Data Format Register 0
#define SPIFMT1            0x01C66854
// SPI Data Format Register 1
#define SPIFMT2            0x01C66858
// SPI Data Format Register 2
#define SPIFMT3            0x01C6685C
// SPI Data Format Register 3
#define INTVEC0            0x01C66860
// SPI Interrupt Vector Register 0
#define INTVEC1            0x01C66864
// SPI Interrupt Vector Register 1

// Definition for GPIO Pin Multiplexing
#define PINMUX1            0x01c40004
#define PINMUX3            0x01c4000c
#define PINMUX4            0x01c40010

// SPI format - Polarity and Phase
// ***NOTE*** It doesn't seem like the SPI Phase for the davinci follows the standard
// phase as described by the motorola architecture. I.E. phase 0 = sample on rising edge of clock
// In the davinci it seems this is opposite.
#define SPI_PHASE                        0
// Set these values to whatever you need
#define SPI_POLARITY                    0
#define SPI_WORDLENGTH                0x10
#define SPI_WORDLENGTH8            0x8
#define TXFULL_NEWDATA_HERE        0x1
#define TXFULL_NO_NEWDATA_HERE    0x0
#define CSSELECT_ACTIVE                0x1
#define CSSELECT_DEACTIVE            0x0
#define SPIEN0_SEL_ONLY                0x2
#define SPIEN1_SEL_ONLY                0x1
#define SPIEN_SEL_BOTH                0x0
#define RXEMPTY_DATA                0x0
#define RXEMPTY_NO_DATA            0x1
#define SPIGCR1_LOOPBACK            0X1
#define SPIGCR1_NO_LOOPBACK        0X1
#define DFSEL                            0x0
#define DMAREQEN                        0x1
#define TXINTENA                        0x1
#define RXINTENA                        0x1
#define TXINTLVL                        0x0
#define RXINTLVL                        0x0

// We will use a 100K buffer to store data
#define DATABUFFER_ALLOC            5000
#define TXBUFFER                        5000
// PRESCALE in bit 15-8 set to whatever you need, SPI_CLK =    SYSCLK4 / (Prescale + 1)    // 26 => 4MHz, 107 => 1MHz, SYSCLK4=108MHz?
#define PRESCALE_SPICLK4M             26
#define PRESCALE_SPICLK2M             53
#define PRESCALE_SPICLK1M             107
#define PRESCALE_SPICLK500K         215
#define CIF_FRAME_SIZE                76800
#define MAX_FRAME_SIZE                  8192
#define MAX_FRAME_NUM                  100
#define GPIO_PIN6                         GPIO(6)
#define GPIO_PIN16                     16
#define GPIO_PIN17                     17
#define GPIO_PIN18                    18
#define FPGA_BUF                        4096

// Macro for accessing a memory location such as a register
//#define SPI_REG(reg)    (*(int *__iomem) IO_ADDRESS(reg))
#define SPI_REG(reg)    (*(volatile unsigned int *) IO_ADDRESS(reg))

#define __REG(addr)   (*(volatile unsigned int *)IO_ADDRESS(addr))
#define REG_PINMUX2     __REG(0x01c40008)

// Version numbers
#define MAJOR_VERSION        245
#define MINOR_VERSION        01

///////////////////////////
// PROTOTYPES
//////////////////////////
/* Declaration of dv_spi.c functions */
int dv_spi_open(struct inode *inode, struct file *filp);
int dv_spi_release(struct inode *inode, struct file *filp);
ssize_t dv_spi_read(struct file *filp, char *buf, size_t count, loff_t *f_pos);
ssize_t dv_spi_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos);
static void dv_spi_exit(void);
static int dv_spi_init(void);

// Global pointer to the clock struct. We use this to start up the LPSoC (local power system on chip)
// so our SPI peripheral has power going to it.
static struct clk *g_clkptr = 0;
static struct cdev cdev;

// Structure that declares the usual file access functions
static struct file_operations dv_spi_fops = {
    .owner = THIS_MODULE,
    .read = dv_spi_read,
    .write = dv_spi_write,
    .open = dv_spi_open,
    .release = dv_spi_release
};

// We will use a 1K buffer to store data
static unsigned char * g_buf;
static unsigned int g_bufcount = 0;

struct FS
{
    unsigned char    FrameBuffer[MAX_FRAME_NUM][MAX_FRAME_SIZE];
    long                FrameLen[MAX_FRAME_NUM];
    long                       FrameNum;
};

long FindFrame = 0;
long FrameLen = 0;
int   Translate = 0;

//////////////////////////////////////////////////////////////

// Called when a userspace program opens the file
int dv_spi_open(struct inode *inode, struct file *filp)
{
    unsigned int control;

    // Power up the SPI hardware by requesting and enabling the clock
    /**/
    g_clkptr = clk_get(NULL, "SPICLK");
    if(g_clkptr <= 0)
        printk("<l>Error could not get the clock\n");
    else
        clk_enable(g_clkptr);
    
    // --------------------------------
    // Configure GPIO Pins for SPI1
    // --------------------------------
    // Enable the SPI pins on the GPIO
    SPI_REG(PINMUX3) |= 0x80000000;//SPI1_SIMO
    SPI_REG(PINMUX4) |= 0x00000015;//SPI1_SCLK, SPI1_SOMI
    printk("0000000 = %x -----%x .\n", SPI_REG(PINMUX3), SPI_REG(PINMUX4));
    // --------------------------------
    // Reset SPI
    // --------------------------------
    control = 0x00000000;
    SPI_REG(SPIGCR0) = control;        // Place SPI peripheral in reset
    printk("11111111 = %x ------ control = %x.\n", SPI_REG(SPIGCR0) , control);
    mdelay(1);                        // Delay for a bit
    
    control=0x00000001;
    SPI_REG(SPIGCR0)=control;        // Remove from reset
    printk("2222222 = %x ------ control = %x.\n", SPI_REG(SPIGCR0) , control );
    // --------------------------------
    // Enable SPI CLK & Master
    // --------------------------------
    control=0x00000003;
    SPI_REG(SPIGCR1)=control;
    printk("3333333 = %x ------ control = %x.\n", SPI_REG(SPIGCR1) , control );
    // -------------------------------
    // Enable loopback mode
    // -------------------------------
    //control = SPI_REG(SPIGCR1);
    //control=control | ( SPIGCR1_LOOPBACK << 16 );
    //SPI_REG(SPIGCR1) = control;

    // --------------------------------
    // Enable pins : DI,DO,CLK
    // --------------------------------
    control=0x00000E00;
    SPI_REG(SPIPC0)=control;
    printk("4444444 = %x ------ control = %x.\n", SPI_REG(SPIPC0)  , control);
    /* --------------------------------
    // Set data format in SPIFMT0 - THIS CAN BE CHANGED BY IOCTL commands
    // SHIFTDIR in bit 20 set to 1 : MSB first
    // POLARITY and PHASE in bit 17, 16 set to 0, 0
    // PRESCALE in bit 15-8 set to whatever you need, SPI_CLK =    SYSCLK5 / (Prescale + 1)    // 26 => 4MHz, 107 => 1MHz, SYSCLK5=108MHz
    // CHARLEN in bit 4-0 set to 16 : 16 bit characters
    -------------------------------- */
    control=0x00000000 | (SPI_POLARITY << 17) | (SPI_PHASE << 16) | (0 << 8) | SPI_WORDLENGTH8;
 //    control=0x00000000 | (SPI_POLARITY << 17) | (SPI_PHASE << 16) | (PRESCALE_SPICLK500K << 8) | SPI_WORDLENGTH8;
//     control=0x00000000 | (SPI_POLARITY << 17) | (SPI_PHASE << 16) | (PRESCALE_SPICLK2M << 8) | SPI_WORDLENGTH8;
//    control=0x00000000 | (SPI_POLARITY << 17) | (SPI_PHASE << 16) | (PRESCALE_SPICLK1M << 8) | SPI_WORDLENGTH8;
    SPI_REG(SPIFMT0)=control;
    printk("5555555 = %x ------ control = %x.\n", SPI_REG(SPIFMT0)  , control);
    // --------------------------------
    // Set data format for used -> SPIFMT0
    // --------------------------------
    control=0x00000000 | (DFSEL << 24);
    SPI_REG(SPIDAT1)=control;
    printk("6666666 = %x ------ control = %x.\n", SPI_REG(SPIDAT1)  , control);
    //--------------------------------
    // Set interrupt
    // -------------------------------
    control=0x00000000 | (DMAREQEN << 16) | (TXINTENA<< 9) | (RXINTENA<< 8);
    SPI_REG(SPIINT)=control;
    printk("7777777 = %x ------ control = %x.\n", SPI_REG(SPIINT)  , control);
    control=0x00000000 | (TXINTLVL<< 9) | (RXINTLVL<< 8);
    SPI_REG(SPILVL)=control;
    printk("8888888 = %x ------ control = %x.\n", SPI_REG(SPILVL)  , control);
    // Set hold time and setup time
    // --------------------------------
    control=0x00000000 | (0x1F << 16) | (0x1F << 24);
    SPI_REG(SPIDELAY)=control;
    printk("9999999 = %x ------ control = %x.\n", SPI_REG(SPIDELAY)  , control);
    // --------------------------------
    // Set Chip Select Default
    // CSHOLD -> 0 -> release SPI_EN0 state after transmission -> bit 28
    // CSNR -> 2 -> Only use SPI_EN0
    //********do you really need this part?********
    // --------------------------------
    control = SPI_REG(SPIDAT1);
    control |= (0x2 << 16);
    SPI_REG(SPIDAT1)=control;
    printk("aaaaaaa = %x ------ control = %x.\n", SPI_REG(SPIDAT1) , control );
    // --------------------------------
    // Enable for transmitting
    // --------------------------------
    control=SPI_REG(SPIGCR1);
    control=control | 1 << 24;    // enable SPIENA
    SPI_REG(SPIGCR1)=control;
    printk("bbbbbbb = %x ------ control = %x.\n", SPI_REG(SPIGCR1)  , control);
    // Zero out our read buffer
    memset(g_buf, 0, DATABUFFER_ALLOC);
    g_bufcount = 0;

    return 0;
}


// Called when a userspace program closes the file
int dv_spi_release(struct inode *inode, struct file *filp)
{
    // Place SPI peripheral into reset
    SPI_REG(SPIGCR0)=0;

    // Remove the SPI output on the GPIO
    SPI_REG(PINMUX3) &= ~0xB800000;

    // Disable the clock thus removing power from the peripheral
    if(g_clkptr)
        clk_disable(g_clkptr);
    g_clkptr = 0;

    return 0;
}


// Reading from the SPI device
ssize_t dv_spi_read(struct file *filp, char *buf, size_t count, loff_t *f_pos)
{
 
    return 0;


}

void sendchar(unsigned char ch)
{
   

    return 0;
}

static int dv_spi_init(void)
{
    int result;
    
    result = register_chrdev (MAJOR_VERSION, MODULE_NAME, &dv_spi_fops);

    if (result)
    {
        printk ("davinci_spi : can't get major number \n");
        return result;
    }

    // Allocate space for the read buffer
    g_buf = kmalloc(DATABUFFER_ALLOC, GFP_KERNEL);
    if (!g_buf)
    {
        result = -ENOMEM;
        dv_spi_exit();
        return result;
    }

    printk("<1>Inserting %s module\n", MODULE_NAME);
    return 0;
}

static void dv_spi_exit(void)
{
    /* Freeing the major number */
    unregister_chrdev(MAJOR_VERSION, MODULE_NAME);

    /* Freeing buffer memory */
    if(g_buf)
        kfree(g_buf);

    if (g_clkptr)
        dv_spi_release(0,0);

    printk("<1>Removing %s module.\n", MODULE_NAME);
}

MODULE_AUTHOR("serdar/Jammy Dane");
MODULE_DESCRIPTION("DaVinci SPI driver for XiGongDa");
MODULE_LICENSE("Dual BSD/GPL");

module_init(dv_spi_init);
module_exit(dv_spi_exit);
/*---------------------driver code end------------------------------------------*/

but when i insmod the spi.ko and when i open the spi device, the printk message is as follows:

00000000 = e15affff - - - - - 5155c555.

11111111 = 0 - - - - - control = 0.

22222222 = 0 - - - - - control = 1.

33333333 = 0 - - - - - control = 3.

44444444 = 0 - - - - - control = e00.

55555555 = 0 - - - - - control = 8.

66666666 = 0 - - - - - control = 0.

77777777 = 0 - - - - - control = 1f1f0000.

88888888 = 0 - - - - - control = 0.

99999999 = 0 - - - - - control = 1.

aaaaaaaa = 0 - - - - - control = 20000.

bbbbbbbb = 0 - - - - - control = 1000000.

It seems that I can not write value to the spi registers, such as SPIGCR0 and so on. can you help me to check it. How to fix it ?

  • Is there anyone who can help me?

    I am urgent in it.

    Thank you all.

  • Not familiar with the DM368. The IO_ADDRESS macro depends on physical memory to be already being mapped to virtual memory. From what I can tell, this is done through a structure in dm635.c (see IO_PHYS) and in the function davinci_common_init(). That said, it's rare to see usage of IO_ADDRESS used to access physical memory. Usually, each driver will do it's own mapping using ioremap(). Makes me wonder if there are limitations to using IO_ADDRESS

    The SPI1 clock name should be "spi_davinci.1" or "spi1".

    Any reason for now using the kernel spi driver? It will require rebuilding the kernel though.

  • thanks for your reply.

    first, I think dm368 is the same as dm365.

    second, I think the problem is not due to IO_ADDRESS macro,because I can read the PINMUX3/4 value.

    the reason I use spi is that: I want to transmit my encoded video frame data to anather board for processing furtherly using spi interface.

    The question I want to ask is  1) any other linux kernel file should i modified? 2)what can i do with the SPI1 clock?


    thank you.

  • This line

    g_clkptr = clk_get(NULL, "SPICLK");

    maybe should be

    g_clkptr = clk_get(NULL, "spi_davinci.1");

    The clock names are in the dm365.c file. Just a guess, maybe you have to enable the power to the SPI1 controller. The DM365 kernel code is bit tough to trace where it starts up clocks and power.

    The alternative is to configure spidev for SPI1. The DM365 kernel appears to already configure SPI0. You could try to clone the SPI0 code for SPI1. The kernel doc is at Documentation/spi/spidev. If see "/dev/spidev" files, the spidev modules has been configured.

  • thank you very much!

    I have fix it according to your suggestion. the problem is that I am not enable the power of the spi1, when i clone spi0 code for spi1, the problem is go awway.

    the code should changed is arch/arm/mach-davinci/dm365.c,arch/arm/mach-davinci/board-dm365-evm.c, and ,arch/arm/mach-davinci/include/dm365.h.

    further more, my linux kernel is 2.6.32.

    thank you again!