Firefly开源社区

打印 上一主题 下一主题

Rk3288的SPI从模式驱动应该怎么写?

30

积分

0

威望

0

贡献

技术小白

积分
30

Rk3288的SPI从模式驱动应该怎么写?

发表于 2020-2-25 09:37:37      浏览:7162 | 回复:0        打印      只看该作者   [复制链接] 楼主
我按照Rk3288的寄存器来配置的,打印的RXDR寄存器和SR寄存器的值都是为0,不知道是我配置错了还是哪里的问题,请各位帮忙解决下。
代码:
#include <linux/device.h>
#include <linux/spi/spi.h>
#include <linux/compiler.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/ioctl.h>//
#include <linux/cdev.h>
#include <linux/string.h>
#include <linux/list.h>
#include <linux/poll.h>
#include <linux/uaccess.h>
#include <linux/ioport.h>


//设置SPI的设备名与主设备号,注意避开那些已经使用的主设备号
#define DEVICE_NAME "spi0_slave" //设备名
#define SPI_MAJOR 237  //主设备号
#define SPI_MINOR 0  //次设备号


//指定SPI寄存器的基地址 ---- SPI0
#define RK3288_SPI_BASE     (0xFF110000)

// SPI0的GPIO基地址 --- SPI0的GPIO复用
#define RK3288_GRF_BASE     (0xFF780000)

/**********************************************************************************/
// 定义SPI寄存器偏移地址
#define SPI_CTRLR0                 0x0000
#define SPI_CTRLR1                0x0004
#define SPI_ENR                        0x0008
#define SPI_SER                        0x000C
#define SPI_BAUDR                0x0010
#define SPI_TXFTLR                0x0014
#define SPI_RXFTLR                0x0018
#define SPI_TXFLR                        0x001C
#define SPI_RXFLR                        0x0020
#define SPI_SR                        0x0024
#define SPI_IPR                        0x0028
#define SPI_IMR                        0x002C
#define SPI_ISR                        0x0030
#define SPI_RISR                        0x0034
#define SPI_ICR                        0x0038
#define SPI_DMACR                0x003C
#define SPI_DMATDLR                0x0040
#define SPI_DMARDLR                0x0044
#define SPI_TXDR                        0x0400        // 0x0400~0x07fc
#define SPI_RXDR                        0x0800        // 0x0800~0x0bfc

/* SPI_CTRLR0 ----- Offset:0x0000 */
#define CR0_OPM_SLAVE           (01 << 20)    // Operation MODE   : Slave Mode
#define CR0_XFM_RECVONLY    (02 << 18)    // Transfer MODE    : receive only
#define CR0_BHT_8BIT                (01 << 13)    // ……
#define CR0_FBM_MSBFIRST      (00 << 12)    // First Bit MODE   : MSB First
#define CR0_FBM_LSBFIRST        (01 << 12)    // First Bit MODE   : LSB First
#define CR0_EM_LITTLE               (00 << 11)    // Endian Mode      : Little Endian
#define CR0_EM_BIG                    (01 << 11)    // Endian Mode      : Big Endian
#define CR0_SCPOL_LOW            (00 << 07)    // CPOL             : IDLE is LOW
#define CR0_SCPH_FIRST             (00 << 06)    // CPHA             : First edge
#define CR0_DFS_8BIT                 (01 << 00)    // Frame Size       : 8bit

/* SPI_ENR ------ Offset:0x0008*/
#define ENR_SPI_DISABLE     (00 << 00)    // Disable SPI
#define ENR_SPI_ENABLE      (01 << 00)    // Enable  SPI

/* SPI_SR ----- Offset:0x0024 */
#define SR_RF_FULL          (01 << 04)    // Receive FIFO Full
#define SR_RF_EMPTY         (01 << 03)    // Receive FIFO Empty
#define SR_SPI_BUSY         (01 << 00)    // SPI is BUSY

/* SPI_DMACR ----- Offset:0x003C*/
#define DMACR_RECV_ENABLE   (01 << 00)    // DMA Recvive Enable
#define DMACR_RECV_DISABLE  (00 << 00)    // DMA Recvive Disable
/**********************************************************************************/

#define MEMSIZE     0x1000
#define MYPRINT(format, ...) printk(format, ##__VA_ARGS__)


static void __iomem *pstSpiReg = NULL;
static void __iomem *TMP = NULL;

static dev_t stSpiDevNum;
//static struct class   *pstSpi_class   = NULL;
//static struct device  *pstSpi_device  = NULL;
//static struct resource    *pstSpi_res     = NULL;

// 定义一个cdev
static struct cdev Rk3288_spi_cdev;
static char s_cRecvData;


// 关闭spi
static int Rk3288_spi_close(struct inode *inode, struct file *filp)
{
    MYPRINT("Rk3288 spi closed.\n");
    return 0;
}

// 打开spi
static int Rk3288_spi_open(struct inode *inode, struct file *filp)
{       
        /* Config SPI -->
                Slave Mode、RecvOnly Mode、MSB First Mode、
                Big Endian、CPOL=CPHA=0 、Data Frame Size = 8bits
        */
        TMP = pstSpiReg + SPI_CTRLR0;
    *(unsigned int *)(TMP) = ( CR0_OPM_SLAVE | CR0_XFM_RECVONLY | CR0_FBM_MSBFIRST | CR0_BHT_8BIT |
                                                           CR0_EM_LITTLE | CR0_SCPOL_LOW | CR0_SCPH_FIRST | CR0_DFS_8BIT );

        TMP = pstSpiReg + SPI_CTRLR1;
        *(unsigned int *)(TMP) = (0x03ff) << 0;

        /* Enable SPI */
    TMP = pstSpiReg + SPI_ENR;
        *(unsigned int *)(TMP) = ENR_SPI_ENABLE;          

        MYPRINT("Rk3288 open spi successfully\n");
    return 0;
}

// spi读读操作
static ssize_t Rk3288_spi_read(struct file *filp, char __user *buf, size_t count, loff_t *f_ops)
{
        int nRet = 0;
       
        TMP = pstSpiReg + SPI_SR;
       
        // get the SPI Status,wait the Recv FIFO FULL
        //while ( !(*(unsigned int *)TMP & SR_RF_FULL) );
    for (nRet = 0; nRet < 10; nRet++)
    {
        MYPRINT("SR reg : %#x\n", *(unsigned int *)TMP);
    }
       
        TMP = pstSpiReg + SPI_RXDR;
       
        s_cRecvData = *(unsigned int *)TMP & 0x0F;
       
        nRet = copy_to_user(buf, &s_cRecvData, count);
        if (0 != nRet)
        {
                MYPRINT("Rk3288 read SPI data error\n");
                return nRet;
        }
       
    return count;
}


// 填充file_operation结构体
static struct file_operations stRk3288_spi_fops =
{
    .owner      = THIS_MODULE,
    .open       = Rk3288_spi_open,
    .read       = Rk3288_spi_read,
    .release    = Rk3288_spi_close,
};

// 初始化设备
static int __init Rk3288_dev_init(void)
{
    int nRet = 0;
    //struct resource *pstGPIO_res = NULL;
    void __iomem *GPIO_GRF_BASE  = NULL;
    void __iomem *GPIO5B_IOMUX   = NULL;

    // 申请或注册设备号
    if (SPI_MAJOR == 0)
    {
        nRet = alloc_chrdev_region(&stSpiDevNum, SPI_MINOR, 1, DEVICE_NAME);
    }
    else
    {
        stSpiDevNum = MKDEV(SPI_MAJOR, SPI_MINOR);
        nRet = register_chrdev_region(stSpiDevNum, 1, DEVICE_NAME);
    }

    if (nRet < 0)
    {
        MYPRINT("Rk3288 can not get device number\n");
        return nRet;
    }

    // 初始化cdev
    cdev_init(&Rk3288_spi_cdev, &stRk3288_spi_fops);

    // 将cdev加入内核
    nRet = cdev_add(&Rk3288_spi_cdev, stSpiDevNum, 1);
    if (nRet < 0)
    {
        MYPRINT("Rk3288 add cdev error\n");
        goto cdev_add_error;
    }

    // 创建class
    #if 0
    pstSpi_class = class_create(THIS_MODULE, "rk3288_spi_class");
    if (pstSpi_class == NULL)
    {
        MYPRINT("Rk3288 class create error\n");
        nRet = -EBUSY;
        goto class_create_error;
    }

    // 创建device
    pstSpi_device = device_create(pstSpi_class, NULL, stSpiDevNum, NULL, "rk3288_spi_drv");
    if (pstSpi_device == NULL)
    {
        MYPRINT("Rk3288 device create error\n");
        nRet = -EBUSY;
        goto device_create_error;
    }

    // 申请物理内存区作为一个资源,申请了其他人就不能用了(不是必须的)----spi
    pstSpi_res = request_mem_region(RK3288_SPI_BASE, MEMSIZE, "Rk3288_spi2");
    if (pstSpi_res == NULL)
    {
        MYPRINT("Rk3288 request mem error\n");
        nRet = -EBUSY;
        goto request_mem_error;
    }


    // GPIO初始化
    /****************************************************************************************/
    pstGPIO_res = request_mem_region(RK3288_GRF_BASE, MEMSIZE, "Rk3288_GRF");
    if (pstGPIO_res == NULL)
    {
        MYPRINT("Rk3288 GRF request mem error\n");
        nRet = -EBUSY;
        goto request_mem_error;
    }
    #endif

    GPIO_GRF_BASE = ioremap(RK3288_GRF_BASE, MEMSIZE);
    if (GPIO_GRF_BASE == NULL)
    {
        MYPRINT("Rk3288 GRF ioremap error\n");
        nRet = -EFAULT;
        goto GRF_ioremap_error;
    }

    GPIO5B_IOMUX = GPIO_GRF_BASE + 0x0050;


    // spi2_clk-----GRF_GPIO8A_IOMUX[13:12]=01
    // spi2_csn0----GRF_GPIO8A_IOMUX[15:14]=01
    // spi2_rx------GRF_GPIO8B_IOMUX[ 1: 0]=01
    // spi2_tx------GRF_GPIO8B_IOMUX[ 3: 2]=01
    // GPIO5B_IOMUX[16:31] = bit15~0 write enable;
    *(unsigned int *)GPIO5B_IOMUX &= ~((0x11 << 8) | (0x11 << 10) | (0x11 << 12) | (0x11 << 14));
    *(unsigned int *)GPIO5B_IOMUX |= (1 << 8) | (1 << 10) | (1 << 12) | (1 << 14);

    //MYPRINT("GPIO5B_IOMUX=%#x\n", *(unsigned int *)GPIO5B_IOMUX);


    // 释放资源,解除映射---GRF
    //release_mem_region(RK3288_GRF_BASE, MEMSIZE);
    iounmap(GPIO_GRF_BASE);
    /***************************************************************************************/

    //IO内存动态映射,由物理地址得到虚拟地址----spi
    pstSpiReg = ioremap(RK3288_SPI_BASE, MEMSIZE);
    if (pstSpiReg == NULL)
    {
        MYPRINT("Rk3288 ioremap error\n");
        nRet = -EFAULT;
        goto spi_ioremap_error;
    }


    MYPRINT("Rk3288 spi slave driver init\n");

    return 0;

// goto select:
/*----------------------------------------------*/
GRF_ioremap_error:
    release_mem_region(RK3288_GRF_BASE, MEMSIZE);   

spi_ioremap_error:
    //release_mem_region(RK3288_SPI_BASE, MEMSIZE);

//request_mem_error:
    //device_destroy(pstSpi_class, stSpiDevNum);

//device_create_error:
    //class_destroy(pstSpi_class);

//class_create_error:
    //cdev_del(&Rk3288_spi_cdev);

cdev_add_error:
    unregister_chrdev_region(stSpiDevNum, 1);
/*----------------------------------------------*/
    return nRet;
}

//module的出口函数---驱动程序的卸载函数
static void __exit Rk3288_dev_exit(void)
{
    unregister_chrdev_region(stSpiDevNum, 1);
    cdev_del(&Rk3288_spi_cdev);
    //device_destroy(pstSpi_class, stSpiDevNum);
    //class_destroy(pstSpi_class);
    //release_mem_region(RK3288_SPI_BASE, MEMSIZE);
    iounmap(pstSpiReg);

    MYPRINT("Rk3288 spi driver exit\n");
}

//module的入口和出口
module_init(Rk3288_dev_init);
module_exit(Rk3288_dev_exit);

//module的描述
MODULE_AUTHOR("huangchengtian");
MODULE_DESCRIPTION("Rk3288 SPI SLAVE Device Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION("V1.0");


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

友情链接 : 爱板网 电子发烧友论坛 云汉电子社区 粤ICP备14022046号-2
快速回复 返回顶部 返回列表