⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dv_spi.c

📁 TI的达芬奇系列dm355使用的spi模块驱动
💻 C
字号:
/*File: dv_spi.c Author: Joshua HintzeE-Mail: joshh at imsar.com Description: A very simple implementation for using the SPIport on the Davinci 6446 platform. This is my first linux driver everso comments are appreciated. Thanks goes to Sean on Davinci Mailing List Limitations: Currently this is written to only use a single Chip Select/SPI_ENO                                                 the reason being that the/SPI_EN1 is multiplexed with the ATA HDDIR lines. Platform Dependencies: Davinci Change History:Date         Author       Description*/  //-------------------------------------------------------------------------- ///////////////////////////// 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 ControllerLPSoC#include <asm/arch/hardware.h> #include <asm/hardware/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#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 // SPI format - Polarity and Phase // ***NOTE*** It doesn't seem like the SPI Phase for the davinci follows thestandard// phase as described by the motorola architecture. I.E. phase 0 = sample onrising edge of clock// In the davinci it seems this is opposite.#define SPI_PHASE                         1// Set these values to whatever you need#define SPI_POLARITY  0 // 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 // 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; // Structure that declares the usual file access functionsstatic struct file_operations dv_spi_fops = {                read: dv_spi_read,                write: dv_spi_write,                open: dv_spi_open,                release: dv_spi_release}; // We will use a 1K read buffer to store datastatic unsigned char *g_readbuf = 0;static unsigned int g_readbufcount = 0;  static int dv_spi_init(void) {                int result;                 /* Registering device */                result = register_chrdev(MAJOR_VERSION, "spi",&dv_spi_fops);                if (result < 0)                 {                                printk("<1>dv_spi: cannot obtain majornumber %d\n", MAJOR_VERSION);                                return result;                }                 // Allocate space for the read buffer                g_readbuf = kmalloc(1024, GFP_KERNEL);                 if (!g_readbuf)                 {                                 result = -ENOMEM;                                dv_spi_exit();                                 return result;                }                  printk("<1>Inserting SPI module\n");                 return 0;} static void dv_spi_exit(void) {                /* 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");}  // Called when a userspace program opens the fileint dv_spi_open(struct inode *inode, struct file *filp){                unsigned int control;                 // Power up the SPI hardware by requesting and enabling theclock                g_clkptr = clk_get(NULL, "SPICLK");                if(g_clkptr <= 0) printk("<l>Error could not get theclock\n");                else clk_enable(g_clkptr);                 // --------------------------------                // Configure GPIO Pins for SPI                 // --------------------------------                // Enable the SPI pins on the GPIO                SPI_REG(PINMUX1) |= 0x100;                 // --------------------------------                // Reset SPI                 // --------------------------------                control=0x00000000;                SPI_REG(SPIGCR0)=control;// Place SPI peripheral in reset                mdelay(1);// Delay for a bit                control=0x00000001;                SPI_REG(SPIGCR0)=control;// Remove from reset                 // --------------------------------                 // Enable SPI CLK & Master                // --------------------------------                control=0x00000003;                SPI_REG(SPIGCR1)=control;                 // --------------------------------                // Enable pins : DI,DO,CLK,EN0                 // --------------------------------                control=0x00000E01;                SPI_REG(SPIPC0)=control;                 /* --------------------------------                // Set data format in SPIFMT0 - THIS CAN BE CHANGED BY IOCTLcommands                // 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)                // CHARLEN in bit 4-0 set to 08 : 8 bit characters                -------------------------------- */                 control=0x00000000 | (SPI_POLARITY << 17) | (SPI_PHASE <<16) | (0x7 << 8) | 0x8;                SPI_REG(SPIFMT0)=control;                 // --------------------------------                // Set data format for used -> SPIFMT0                // --------------------------------                control=0x00000000 | (0x00 << 24);                 SPI_REG(SPIDAT1)=control;                  // --------------------------------                // Set hold time and setup time                // --------------------------------                control=0x00000000 | (0x03 << 16) | (0x06 << 24);                 SPI_REG(SPIDELAY)=control;                  // --------------------------------                // Set Chip Select Default                // CSHOLD -> 0 -> release SPI_EN0 state after transmission-> bit 28                // CSNR -> 2 -> Only use SPI_EN0                // --------------------------------                 control=SPI_REG(SPIDAT1);                control|= (0x2 << 16);                SPI_REG(SPIDAT1)=control;                 // --------------------------------                // Enable for transmitting                // --------------------------------                 control=SPI_REG(SPIGCR1);                control=control | 1 << 24;    // enable SPIENA                SPI_REG(SPIGCR1)=control;                 // Zero out our read buffer                memset(g_readbuf, 0, 1024);                g_readbufcount = 0;                 return 0;}  // Called when a userspace program closes the fileint 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(PINMUX1) &= ~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 devicessize_t dv_spi_read(struct file *filp, char *buf, size_t count, loff_t*f_pos){//            printk("<1>Attempting to read %d bytes and we only have %dbytes\n",count,g_readbufcount);     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 devicessize_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;     // 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);     // 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);                control = 0x00000000 | (0x1 << 28) | (0x2 <<16) | spiData; // Hold the chip select line between multibytes        SPI_REG(SPIDAT1) = control;        if(i == (count -1))            SPI_REG(SPIDAT1) = 0x00000000 | (0x2 << 16) | spiData; // Remove the chip select hold        control = SPI_REG(SPIBUF);        while(control & (1 << 29))// Wait until the TX data has been transmitted            {            // Check for data received            if(!(control & (1 << 31)))            {                            // We havejust read a byte of data, store it.                 if(g_readbufcount < 1024)                {                //                printk("<1>Read in byte value =  %d!\n",count);                                 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 %d\n",control & 0xFF);                // We havejust read a byte of data, store it.                     if(g_readbufcount < 1024)                    {                    //                    printk("<1>Read in byte value =  %d\n",control);                                         g_readbuf[g_readbufcount] = control & 0xFF;                                         g_readbufcount++;                                         ReadByte = 1;                    }                }                control = SPI_REG(SPIBUF);           }       }                 return count;} MODULE_LICENSE("Dual BSD/GPL");module_init(dv_spi_init);module_exit(dv_spi_exit);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -