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.

SPI driver for DM644x

Hi,

I am using Montavista 5.0 and DM6441 for my custom board. I want to use SPI to comunicate with FPGA. But I found that there is no SPI driver for DM644x in the kernel. And I  know that there is no /dev/spi interface, so how can I do it? How can I read/write SPI in the user space?

Can anyone help me?

Thanks,

Rain

  • Hi Rain,

    For accessing SPI devices from user space, you need spidev support. Please check Documentation/spi/spidev file for information.

    SPI driver was not tested on DM644x EVM because of a lack of SPI device on board.

    Thanks,

    Sekhar

  • Hi Sekhar,

    You are so helpful! Thanks, I will do some tests based on this document.

    Best regards,

    Rain

  • Hi Sekhar,

    According to Documentation/spi/spidev, I change the "modalias" entry to "spidev", so now spidev driver can be executed. But why I can't find /dev/spidevB.C interface as document said? I find that spidev_probe function is not called, why?

    Best regards,

    Rain

  • //This is davinci_spi_platform.c I changed

    #include <linux/config.h>
    #include <linux/device.h>
    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/types.h>
    #include <linux/init.h>
    #include <linux/resource.h>
    #include <linux/spi/spi.h>
    #include <linux/spi/davinci_spi.h>
    #include <linux/spi/flash.h>
    #include <linux/device.h>
    #include <linux/mtd/mtd.h>
    #include <linux/mtd/partitions.h>
    #include <linux/platform_device.h>
    #include <linux/spi/at25xxA_eeprom.h>

    #include <asm/arch/hardware.h>
    #include <linux/spi/davinci_spi_master.h>
    #include <asm/arch/cpu.h>
    #include <linux/io.h>

    #define PINMUX1REG __REG(0x01c40004)
    #define SPI_ENABLE (1 << 8)

    static struct davinci_spi_platform_data dm355_spi_platform_data = {
     .initial_spmode = 0,
     .bus_num = 0,
     .max_chipselect = 2,
     .activate_cs = NULL,
     .deactivate_cs = NULL,
     .sysclk = 108 * 1000 * 1000,
    };

    static struct davinci_spi_platform_data dm646x_spi_platform_data = {
     .initial_spmode = 0,
     .bus_num = 0,
     .max_chipselect = 2,
     .activate_cs = NULL,
     .deactivate_cs = NULL,
     .sysclk = 67.5 * 1000 * 1000,
    };

    //Rain is here
    static struct davinci_spi_platform_data dm6441_spi_platform_data = {
     .initial_spmode = 0,
     .bus_num = 0,
     .max_chipselect = 4,
     .activate_cs = NULL,
     .deactivate_cs = NULL,
     .sysclk = 67.5 * 1000 * 1000,
    };


    static struct resource dm646x_spi_resources[] = {
     [0] = {
            .start = DAVINCI_SPI_BASE,
            .end = DAVINCI_SPI_BASE + (SZ_4K/2),
            .flags = IORESOURCE_MEM,
            },
     [1] = {
            .start = IRQ_SPINT0,
            .end = IRQ_SPINT0,
            .flags = IORESOURCE_IRQ,
            },
    };

    static struct resource dm355_spi_resources[] = {
     [0] = {
            .start = DM355_SPI0_BASE,
            .end = DM355_SPI0_BASE + (SZ_4K/2),
            .flags = IORESOURCE_MEM,
            },
     [1] = {
            .start = IRQ_DM355_SPINT0_0,
            .end = IRQ_DM355_SPINT0_0,
            .flags = IORESOURCE_IRQ,
            },
    };

    //Rain is here
    static struct resource dm6441_spi_resources[] = {
     [0] = {
            .start = DAVINCI_SPI_BASE,
            .end = DAVINCI_SPI_BASE + (SZ_4K/2),
            .flags = IORESOURCE_MEM,
            },
     [1] = {
            .start = IRQ_SPINT0,
            .end = IRQ_SPINT0,
            .flags = IORESOURCE_IRQ,
            },
    };

    //Rain is here
    static struct platform_device davinci_spi_device = {
     .name = "dm_spi",
     .id = 0,
     .num_resources = ARRAY_SIZE(dm6441_spi_resources),
     .resource = dm6441_spi_resources,
    };

    #if defined(CONFIG_DAVINCI_SPI_EEPROM_MODULE) || \
        defined(CONFIG_DAVINCI_SPI_EEPROM)
    static struct mtd_partition spi_partitions[] = {
     /* UBL in first sector */
     {
      .name = "UBL",
      .offset = 0,
      .size = SZ_16K,
      .mask_flags = MTD_WRITEABLE,
      },
     /* User data in the next sector */
     {
      .name = "data",
      .offset = MTDPART_OFS_APPEND,
      .size = MTDPART_SIZ_FULL,
      .mask_flags = 0,
      }
    };

    struct davinci_eeprom_info davinci_8k_spi_eeprom_info = {
     .eeprom_size = 8192,
     .page_size = 32,
     .page_mask = 0x001F,
     .chip_sel = SCS0_SELECT,
     .parts = NULL,
     .nr_parts = 0,
     .commit_delay = 3,
    };

    struct davinci_eeprom_info davinci_32k_spi_eeprom_info = {
     .eeprom_size = 32768,
     .page_size = 64,
     .page_mask = 0x003F,
     .chip_sel = SCS0_SELECT,
     .parts = spi_partitions,
     .nr_parts = ARRAY_SIZE(spi_partitions),
     .commit_delay = 5,
    };
    #endif

    /*Put slave specific information in this array.*/
    /*For more information refer the table at the end of file tnetd84xx_spi_cs.c*/
    static struct spi_board_info dm6467_spi_board_info[] = {
    #if defined(CONFIG_DAVINCI_SPI_EEPROM_MODULE) || \
        defined(CONFIG_DAVINCI_SPI_EEPROM)
           {
     .modalias = DAVINCI_SPI_EEPROM_NAME,
     .platform_data = &davinci_32k_spi_eeprom_info,
     .mode = SPI_MODE_0,
     .irq = 0,
     .max_speed_hz = 2 * 1000 * 1000 /* max sample rate at 3V */ ,
     .bus_num = 0,
     .chip_select = 0,
     },
    #endif
    };

    static struct spi_board_info dm355_spi_board_info[] = {
    #if defined(CONFIG_DAVINCI_SPI_EEPROM_MODULE) || \
        defined(CONFIG_DAVINCI_SPI_EEPROM)
           {
     .modalias = DAVINCI_SPI_EEPROM_NAME,
     .platform_data = &davinci_8k_spi_eeprom_info,
     .mode = SPI_MODE_0,
     .irq = 0,
     .max_speed_hz = 2 * 1000 * 1000 /* max sample rate at 3V */ ,
     .bus_num = 0,
     .chip_select = 0,
     },
    #endif
    };

    //Rain is here
    static struct spi_board_info dm6441_spi_board_info[] = {
     {
     .modalias = "spidev",
     .platform_data = NULL,
     .mode = SPI_MODE_0,
     .irq = 0,
     .max_speed_hz = 2 * 1000 * 1000 /* max sample rate at 3V */ ,
     .bus_num = 0,
     .chip_select = 0,
     },
    };


    /*
     * This function initializes the GPIOs used by the SPI module
     * and it also registers the spi mastere device with the platform
     * and the spi slave devices with the spi bus
     */
    static int __init davinci_spi_board_init(void)
    {
     int ret = 0;
     int size;
     struct spi_board_info *davinci_board_info;

     if (cpu_is_davinci_dm6467()) {
      davinci_board_info = dm6467_spi_board_info;
      size = ARRAY_SIZE(dm6467_spi_board_info);
      davinci_spi_device.resource = dm646x_spi_resources;
      davinci_spi_device.num_resources =
          ARRAY_SIZE(dm646x_spi_resources);
      davinci_spi_device.dev.platform_data =
          &dm646x_spi_platform_data;
     } else if (cpu_is_davinci_dm355()) {
      davinci_board_info = dm355_spi_board_info;
      size = ARRAY_SIZE(dm355_spi_board_info);
      davinci_spi_device.resource = dm355_spi_resources;
      davinci_spi_device.num_resources =
          ARRAY_SIZE(dm355_spi_resources);
      davinci_spi_device.dev.platform_data = &dm355_spi_platform_data;
     } else {
      //pr_info("davinci_spi_board_init: NO spi support\n");
      //return 0;
      pr_alert("davinci_spi_board_init: DM6441\n");
      //pr_alert("PINMUX1REG: %x\n", PINMUX1REG);
      PINMUX1REG |= SPI_ENABLE;
      //pr_alert("PINMUX1REG: %x\n", PINMUX1REG);
      davinci_board_info = dm6441_spi_board_info;
      size = ARRAY_SIZE(dm6441_spi_board_info);
      davinci_spi_device.resource = dm6441_spi_resources;
      davinci_spi_device.num_resources =
          ARRAY_SIZE(dm6441_spi_resources);
      davinci_spi_device.dev.platform_data =
          &dm6441_spi_platform_data;
     }

     /* Register the slave devices present in the board with SPI subsytem */
     ret = spi_register_board_info(davinci_board_info, size);

     /* Register the master controller with platform */
     (void)platform_device_register(&davinci_spi_device);

     return 0;
    }

    static void __exit davinci_spi_board_exit(void)
    {
     /* nothing to be done */
    }

    module_init(davinci_spi_board_init);
    module_exit(davinci_spi_board_exit);

  • Hi Rain,

    Rain Peng said:
    But why I can't find /dev/spidevB.C interface as document said?

    'B' stands for bus number and 'C' for chip-select number. So chip-select 0 on SPI bus 0 will appear as /dev/spidev0.0

    Rain Peng said:
    I find that spidev_probe function is not called, why?

    I dont think SPI device support is enabled by default. Can you make sure CONFIG_SPI_SPIDEV is enabled from from the SPI menu in kernel configuration?

    Thanks,

    Sekhar

  • Hi Sekhar,

    I have checked the .config file, CONFIG_SPI_SPIDEV is enabled.

    If I cat /proc/devices, I see SPI with major number 153. There is also /sys/class/spidev folder, but there is nothing in this folder.

    Best regards,

    Rain

  • Can anyone help on this?

    Thanks,

    Rain

  • I finally solve this issue. I copy the driver to this thread for helping someone else on similar issue.

    /*

    File: dv_spi.c

    Author: Joshua Hintze (joshh@imsar.com )


    Description: A very simple implementation for using the SPI

    port on the Davinci 644x platform. Thanks for Joshua Hintze's sharing


    Thanks goes to Sean on Davinci Mailing List

    Limitations: Currently this is written to only use a single Chip Select to read/write EEPROM


    Platform Dependencies: Davinci


    Change History:

    Date               Author       Description

    2010/08/15  Rain Peng   Porting to DM6441 for read/write EEPROM, should mknod -m 666 /dev/spi c 60 1

    */  

    //

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

    // INCLUDES

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


    #include <linux/init.h>

    #include <linux/module.h>

    #include <linux/kernel.h>

    #include <linux/delay.h>              // udelay()

    #include <linux/fs.h>                 // everything...

    #include <asm/uaccess.h>              // copy_from/to_user

    // Definition for SPI Base Address and the local Power or Sleep Controller LPSoC

    #include <asm/arch/hardware.h> 

    #include <asm/arch/clock.h>

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

    // 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);


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

    // DEFINITIONS & GLOBALS

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

    // Register definitions to control the SPI


    #define SPIGCR0                                   0x01C66800  //SPI Global Control Register0

    #define SPIGCR1                                   0x01C66804  //SPI Global Control Register1

    #define SPIINT                                    0x01C66808  //SPI Interrupt Register

    #define SPILVL                                    0x01C6680c  //SPI Interrupt Level Register

    #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

    #ifndef PINMUX1REG

    #define PINMUX1REG                                0x01C40004

    #endif

    //use GPIO[7]

    #define GPIO_DIR01                                0x01C67010

    #define GPIO_OUT_DATA01                           0x01C67014

    #define GPIO_SET_7                                (1 << 7)

    #define GPIO_CLR_7                                ~(1 << 7)


    // 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               1

    #define SPI_POLARITY            0

    #define SPI_PRESCALE            16


    // Macro for accessing a memory location such as a register

    #define SPI_REG(reg)    (*(int *__iomem) IO_ADDRESS(reg))

    // Version numbers

    #define MAJOR_VERSION           60

    #define MINOR_VERSION           01


    //Max Read/Write buff size

    #define MAX_BUF_SIZE            2048


    // 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;


    // We will use a 1K read buffer to store data

    static unsigned char *g_readbuf = 0;

    static unsigned int g_readbufcount = 0;

    static unsigned int spidat1 = 0;



    // Called when a userspace program opens the file

    int dv_spi_open(struct inode *inode, struct file *filp)

    {

    unsigned int control;

    printk("<1>open +\n");


    // --------------------------------

    // Configure GPIO Pins for SPI 

    // --------------------------------

    // Enable the SPI pins on the GPIO

    SPI_REG(PINMUX1REG) |= 0x100;

    //let GPIO7 pin as output pin

    control = SPI_REG(GPIO_DIR01);

    //printk("<1>GPIO_DIR01 = 0x%x\n", SPI_REG(GPIO_DIR01));

    SPI_REG(GPIO_DIR01) = control & GPIO_CLR_7;

    //printk("<1>GPIO_DIR01 = 0x%x\n", SPI_REG(GPIO_DIR01));

    //pull GPIO7 to high

    control = SPI_REG(GPIO_OUT_DATA01);

    //printk("<1>GPIO_OUT_DATA01 = 0x%x\n", SPI_REG(GPIO_OUT_DATA01));

    SPI_REG(GPIO_OUT_DATA01) = control | GPIO_SET_7;

    //printk("<1>GPIO_OUT_DATA01 = 0x%x\n", SPI_REG(GPIO_OUT_DATA01));

    // 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);

    // --------------------------------

    // Reset SPI 

    // --------------------------------

    control = 0x00000000;

    SPI_REG(SPIGCR0) = control;

    mdelay(1); // Delay for a bit

    // Remove from reset

    control = 0x00000001;

    SPI_REG(SPIGCR0) = control;

    //printk("<1>SPIGCR0 = 0x%x\n", SPI_REG(SPIGCR0));

    // -------------------------------- 

    // Enable SPI CLK & Master

    // --------------------------------

    control = 0

            | ( 0 << 24 )

            | ( 0 << 16 )  //loopback test

            | ( 1 << 1 )

            | ( 1 << 0 );

    SPI_REG(SPIGCR1) = control;

    //printk("<1>SPIGCR1 = 0x%x\n", SPI_REG(SPIGCR1));

    // --------------------------------

    // Enable pins : DI,DO,CLK,EN0,EN1, set EN0 to o, EN1 to 1

    // --------------------------------

    control = 0

            | ( 1 << 11 )   // DI

            | ( 1 << 10 )   // DO

            | ( 1 << 9 )    // CLK

            | ( 1 << 1 )    // EN1

            | ( 1 << 0 );   // EN0

    SPI_REG(SPIPC0) = control;

    //printk("<1>SPIPC0 = 0x%x\n", SPI_REG(SPIPC0));


    /* --------------------------------

    // Set data format in SPIFMT0 - THIS CAN BE CHANGED BY IOCTL commands

    // SHIFTDIR in bit 20 set to 0 : MSB first 

    // POLARITY and PHASE in bit 17, 16 set to 0, 1

    // PRESCALE in bit 15-8 set to whatever you need, SPI_CLK = SYSCLK5 / (Prescale + 1)

    // CHARLEN in bit 4-0 set to 08 : 8 bit characters

    -------------------------------- */ 

    control = 0

            | ( 0 << 20 )   // SHIFTDIR

            | ( 0 << 17 )   // Polarity

            | ( 1 << 16 )   // Phase

            | ( 50 << 8 )    // Prescale

            | ( 8 << 0 );   // Char Len

    SPI_REG(SPIFMT0) = control;

    //printk("<1>SPIFMT0 = 0x%x\n", SPI_REG(SPIFMT0));

    // --------------------------------

    // Set data format for used 

    // --------------------------------

    spidat1 = 0

            | ( 1 << 28 )   // CSHOLD

            | ( 0 << 24 )   // Format [0]

            | ( 2 << 16 )   // CSNR   [only CS0 enbled]

            | ( 0 << 0 );   //Data

    control = spidat1; 

    SPI_REG(SPIDAT1) = control;

    //printk("<1>SPIDAT1 = 0x%x\n", SPI_REG(SPIDAT1));

    // --------------------------------

    // Set hold time and setup time

    // --------------------------------

    control = 0

            | ( 6 << 24 )   // C2TDELAY

            | ( 7 << 16 );  // T2CDELAY

    SPI_REG(SPIDELAY) = control;

    //printk("<1>SPIDELAY = 0x%x\n", SPI_REG(SPIDELAY));

    // --------------------------------

    // Set chip select default pattern-

    // --------------------------------

    control = 0

            | ( 1 << 1 )    // EN1 inactive high

            | ( 1 << 0 );   // EN0 inactive high 

    SPI_REG(SPIDEF) = control;

    //printk("<1>SPIDEF = 0x%x\n", SPI_REG(SPIDEF));

    // --------------------------------

    // Enable for transmitting

    // -------------------------------- 

    control = SPI_REG(SPIGCR1);

    control = control | 1 << 24;    // enable SPIENA

    SPI_REG(SPIGCR1) = control;

    printk("<1>SPIGCR1 = 0x%x\n", SPI_REG(SPIGCR1));

    // Zero out our read buffer

    memset(g_readbuf, 0, MAX_BUF_SIZE);

    g_readbufcount = 0;


    return 0;

    }


    // Called when a userspace program closes the file

    int dv_spi_release(struct inode *inode, struct file *filp)

    {

    printk("<1>close\n");


    // Place SPI peripheral into reset

    SPI_REG(SPIGCR0) = 0;

    // Remove the SPI output on the GPIO

    SPI_REG(PINMUX1REG) &= ~0x100;

    // 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)

    {

    //printk("<1>read\n");

    if(g_readbufcount == 0) return 0; // No data

    // See if there is enough available

    if(count > g_readbufcount) count = g_readbufcount;

    // Transferring data to user space 

    copy_to_user(buf,g_readbuf,count);

    // Now shift the memory down

    memmove(&g_readbuf[0],&g_readbuf[count],g_readbufcount-count);

    g_readbufcount -= count;

    // Advance the file pointer

    *f_pos += count;

    return count;

    }


    // Writing to the SPI device

    ssize_t dv_spi_write(struct file *filp, const char *buf, size_t count,

    loff_t *f_pos)

    {

    unsigned char spiData;

    size_t i;

    unsigned int control;

    unsigned int ReadByte;

    //printk("<1>write\n");

    // Wait until the TX buffer is clear

    control = SPI_REG(SPIBUF);

    while(control & (1 << 29))                            //Wait until the TX data has been transmitted

    control = SPI_REG(SPIBUF);

    //printk("<1>SPIBUF 1: 0x%x\n", SPI_REG(SPIBUF));

    // Write out data one byte at a time

    for(i = 0; i < count; i++)

    {

    ReadByte = 0;

    // Send the data

    copy_from_user(&spiData, buf+i, 1);

    if(i == (count - 1))

    SPI_REG(SPIDAT1) = (spidat1 & 0x0fffffff ) | spiData; // Remove the chip select hold

    else

    SPI_REG(SPIDAT1) = spidat1 | spiData; // Hold the chip select line between multibytes

    //printk("<1>SPIDAT1 1: 0x%x\n", SPI_REG(SPIDAT1));

    control = SPI_REG(SPIBUF);

    //printk("<1>SPIBUF 2: 0x%x\n", SPI_REG(SPIBUF));

    while(control & (1 << 29))// Wait until the TX data has been transmitted

    {

    // Check for data received

    if(!(control & (1 << 31)))

    {

    // We have just read a byte of data, store it.

    if(g_readbufcount < MAX_BUF_SIZE)

    {

    //

    //printk("<1>Read in byte count = %d, value =  %x!\n",count, control & 0xFF);

    g_readbuf[g_readbufcount] = control & 0xFF;

    g_readbufcount++;

    ReadByte = 1;

    }

    }

    control = SPI_REG(SPIBUF);

    }

    // Make sure we have always read in a byte

    while(!ReadByte)

    {

    // Check for data received

    if(!(control & (1 << 31)))

    {

    //printk("<1>we received a byte with value %x\n",control & 0xFF);

    // We have just read a byte of data, store it.

    if(g_readbufcount < MAX_BUF_SIZE)

    {

    //printk("<1>Read in byte count = %d, value =  %x!\n",count, control & 0xFF);

    g_readbuf[g_readbufcount] = control & 0xFF;

    g_readbufcount++;

    ReadByte = 1;

    }

    }

    control = SPI_REG(SPIBUF);

    }

    }

    return count;

    }


    ssize_t dv_spi_ioctl(struct inode *inode, struct file *filp,

    unsigned int cmd, unsigned long arg)

    {

    return 0;

    }


    // 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,

    .ioctl = dv_spi_ioctl,

    .open = dv_spi_open,

    .release = dv_spi_release

    };


    static int dv_spi_init(void) 

    {

    int result;

    unsigned int control;

    gpio_direction_output(37,0);


    /* Registering device */

    result = register_chrdev(MAJOR_VERSION, "spi",

    &dv_spi_fops);

    if (result < 0) 

    {

    printk("<1>dv_spi: cannot obtain major number %d\n", MAJOR_VERSION);

    return result;

    }

    // Allocate space for the read buffer

    g_readbuf = kmalloc(MAX_BUF_SIZE, GFP_KERNEL); 

    if (!g_readbuf) 

    result = -ENOMEM;

    dv_spi_exit(); 

    return result;


    //printk("<1>PLL_SYS5 = 0x%x\n", SPI_REG(0x01c40964));

    //printk("<1>PLL_SYS5_STAT = 0x%x\n", SPI_REG(0x01c40950));

    printk("<1>Inserting SPI module\n"); 

    return 0;

    }


    static void dv_spi_exit(void) 

    {

    //pull GPIO7 to low  

    //unsigned int control;

    //control = SPI_REG(GPIO_OUT_DATA01);

    //printk("<1>GPIO_OUT_DATA01 = 0x%x\n", SPI_REG(GPIO_OUT_DATA01));

    //SPI_REG(GPIO_OUT_DATA01) = control & GPIO_CLR_7;

    //printk("<1>GPIO_OUT_DATA01 = 0x%x\n", SPI_REG(GPIO_OUT_DATA01));


    /* Freeing the major number */

    unregister_chrdev(MAJOR_VERSION, "spi");

    /* Freeing buffer memory */

    if(g_readbuf)

    kfree(g_readbuf);

    if (g_clkptr) 

    dv_spi_release(0,0);

    printk("<1>Removing SPI module\n");

    }



    MODULE_LICENSE("Dual BSD/GPL");

    module_init(dv_spi_init);

    module_exit(dv_spi_exit);

  • How did you managedd to make the system to create  the spiA.B file in the /dev folder. I am going through the same process than you on a dm365 and I got the spi dirver compiled but when I load it no file is created in the /dev folder to access it. Thanks Jesus Lopez

  • Please see the head of my answer : mknod -m 666 /dev/spi c 60 1