OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 698|回复: 1

imxu6ll spi device驱动 使用dma

[复制链接]

18

主题

47

帖子

0

精华

初级会员

Rank: 2

积分
123
金钱
123
注册时间
2016-9-5
在线时间
21 小时
发表于 2024-3-30 17:58:03 | 显示全部楼层 |阅读模式
1金钱
imxu6ll  spi  device驱动 使用dma,,有朋友调通吗?  不使用dma的是调通了,,,

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>



#include <linux/compat.h>
#include <linux/module.h>
#include <linux/videodev2.h>
#include <linux/v4l2-subdev.h>
#include <media/v4l2-dev.h>
#include <media/v4l2-fh.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-ioctl.h>

#include <linux/compiler.h>
#include <linux/uaccess.h>

#include <linux/spi/spi.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>



/*
        mount   /dev/mmcblk0p1  /mnt
        umount  /mnt

compatible = "test,max31865";  驱动匹配字符串


        arm-linux-gnueabihf-gcc   app.c   -o app
       
*/

//定义一个总的结构体--使用方便点
struct my_devStru
{
        dev_t                         dev_number;
       
        struct cdev         my_cdev;         // 字符设备结构--cdev-init使用
        struct class         *my_class;         // 设备类指针
        struct device   *my_device;
       
        char name[64];
       
        struct spi_device *spi_dev;
};

struct my_devStru  my_dev; //我这里使用静态的--实际也可以使用动态的.采用内存分配的方式






static int my_open(struct inode *inode, struct file *file)
{
        printk("my_open .\r\n");

        file->private_data = &my_dev;//挂载全局结构体对象
       
        return 0;
}

int my_release(struct inode *inode, struct file *file)
{
        printk("my_release .\r\n");

        return 0;
}


struct max31865_dataStru
{
        unsigned int   tempture;  //温度--是当大100倍的-2位小数
};

#define MY_CMD_READ     _IOWR('k',  1, struct max31865_dataStru)


static long my_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
{
        printk("my_ioctl  .\n");
       
       
        switch(cmd)
        {
                case MY_CMD_READ://返回一个温度数据
                        printk("my_ioctl  MY_CMD_READ. \n");

                        struct my_devStru * p_my_dev = 0;
                        p_my_dev = (struct my_devStru *)(fp->private_data);
                       

                        struct max31865_dataStru * argg  = arg;
                        //argg->tempture =  35.67*100;
                        //printk("my_ioctl argg->tempture = %d. \n",  argg->tempture  );


                        //直接采集温度回来
                       

                        //读取一次温度值
                        //测试读取 max31865的寄存器
                        {
                                int ret = -1;
                                //unsigned char txdata[8];
                                //unsigned char rxdata[8];

                                uint16_t dtemp[2];
                                float temps;
                               
                                struct spi_transfer transfer = {0};
                                struct spi_message         msg = {0};

                                dma_addr_t  tx_dma = 0;
                                dma_addr_t  rx_dma = 0;

                                if (dma_set_coherent_mask(  &(my_dev.spi_dev->dev) , DMA_BIT_MASK(32)))
                                {
                                        printk("dma_set_coherent_mask  error . \n");
                                        return -1;
                                }
               
                                unsigned char *txdata = dma_alloc_coherent( &(my_dev.spi_dev->dev), 256, &tx_dma, GFP_KERNEL);
                                   unsigned char *rxdata = dma_alloc_coherent( &(my_dev.spi_dev->dev), 256, &rx_dma, GFP_KERNEL);
                               
                                if( (txdata == 0)||(rxdata == 0) )
                                {
                                        printk("my_ioctl dma_alloc_coherent error . \n");
                                        return -1;
                                }
                                else
                                {
                                        printk("my_ioctl dma_alloc_coherent ok . \n");
                                }
               

                                //1
                                //测试--再读取回来试试
                                //SPI Single-Byte read  单次写模式--2字节写完后cs会拉高
                                transfer.tx_buf = txdata;
                                transfer.rx_buf = rxdata;
               
                                txdata[0] = 0x01;//要读的寄存器地址 --最高位为0
                                 transfer.tx_dma = tx_dma;
                                 transfer.len = 2;//2个字节
                                transfer.delay_usecs = 1000;
                               
                                rxdata[0]=0;//用不上--丢弃
                                rxdata[1]=0;
                                 transfer.rx_dma = rx_dma;


                                msg.is_dma_mapped = 1;
                                spi_message_init( &msg );
                                spi_message_add_tail( &transfer ,   &msg );

                                msg.is_dma_mapped = 1;
                               
                                 ret = spi_sync( p_my_dev->spi_dev , &msg );        /* 同步发送 */
                            if(ret ==0 )
                            {
                                    printk("if(ret ==0 )   configute reg  read ok.   \n");
                                    printk("rxdata[1] = 0x%x .\n", rxdata[1] );
                            }
                            else
                            {
                                    printk("configute reg  read error. \n");
                            }

                                dtemp[0] = rxdata[1] ;



                                //2
                                transfer.tx_buf = txdata;
                                transfer.rx_buf = rxdata;
                               
                                txdata[0] = 0x02;//要读的寄存器地址 --最高位为0
                                 transfer.tx_dma = tx_dma;
                                 transfer.len = 2;//2个字节
                                transfer.delay_usecs = 1000;
                               
                                rxdata[0]=0;//用不上--丢弃
                                rxdata[1]=0;
                                 transfer.rx_dma = rx_dma;

                                 msg.is_dma_mapped = 1;
                                spi_message_init( &msg );
                                spi_message_add_tail( &transfer ,   &msg );

                                msg.is_dma_mapped = 1;
                               
                                 ret = spi_sync( p_my_dev->spi_dev , &msg );        /* 同步发送 */
                            if(ret ==0 )
                            {
                                    printk("if(ret ==0 )   configute reg  read ok.   \n");
                                    printk("rxdata[1] = 0x%x .\n", rxdata[1] );
                            }
                            else
                            {
                                    printk("configute reg  read error. \n");
                            }

                                dtemp[1] = rxdata[1] ;

                               
                               
                                //3--计算
                                uint16_t data_temp =0 ;
                               
                                data_temp        = (dtemp[0] << 8) | dtemp[1];  /* Get 15Bit DATA; */
                                data_temp        >>= 1; /* Get 15Bit DATA; */
                                printk("15bit data  = data_temp = %d .\n",  data_temp );

                                argg->tempture =  data_temp;
                                printk("my_ioctl argg->tempture = %d.   .\n",  argg->tempture  );

                               
                                #if 0 // 下面的让APP应用层去算
                                  temps=(temps*430)/32768;//是电阻值
                                 
                               
                                //计算出摄氏度
                                  temps=(temps-100)/0.385055;//A gruad
                               
                                temps = temps  - 0.94;//是实际温度值

                                temps = temps *100; //放大100倍
                                argg->tempture =  temps;
                                printk("my_ioctl argg->tempture = %d.  fangDa100Bei .\n",  argg->tempture  );
                                #endif

                                printk("my_ioctl dma_free_coherent .\n");
                                dma_free_coherent(  &(my_dev.spi_dev->dev), 256, txdata , tx_dma );
                                dma_free_coherent(  &(my_dev.spi_dev->dev), 256, rxdata , rx_dma );
                        }
                       
                        break;
                       
                       
                default :
                        printk("default  no  cmd.\n");
                        break;
                       
        }
                                       
        return 0;
       
}




// 文件操作结构体占位符(实际项目中需要根据需求实现)
static struct file_operations my_fops =
{
    .owner                         = THIS_MODULE,
    .open                         = my_open,
    .release                 = my_release,
        .unlocked_ioctl = my_ioctl,
};

static int   my_device_init(void)
{
    int ret = -1;
       
        printk("my_device_init .\r\n");
       
       
    // 动态分配设备号
    ret = alloc_chrdev_region(&my_dev.dev_number, 0, 1, "my_device"); //从0开始-取用一个
    if (ret < 0)
        {
        printk(KERN_ERR "Unable to allocate char dev number\n");
        return ret;
    }
       
        printk("major = %d .\r\n",  MAJOR(my_dev.dev_number) );
        printk("minor = %d .\r\n",  MINOR(my_dev.dev_number) );



    // 初始化并添加cdev结构
    cdev_init(&my_dev.my_cdev, &my_fops);
    my_dev.my_cdev.owner = THIS_MODULE;
    ret = cdev_add(&my_dev.my_cdev, my_dev.dev_number, 1);
    if (ret < 0)
        {
        device_destroy(my_dev.my_class, my_dev.dev_number);
        class_destroy(my_dev.my_class);
        unregister_chrdev_region(my_dev.dev_number, 1);
        return ret;
    }


         // 创建设备类
    my_dev.my_class = class_create(THIS_MODULE, "my_class");
    if(IS_ERR(my_dev.my_class))
        {
        unregister_chrdev_region(my_dev.dev_number, 1);
        return PTR_ERR(my_dev.my_class);
    }
       
    // 创建设备文件---自动创建设备
        sprintf( my_dev.name , "my_device" );
        my_dev.my_device = device_create(my_dev.my_class, NULL, my_dev.dev_number, NULL, my_dev.name );
       
    if( my_dev.my_device == NULL )
        {
        class_destroy(my_dev.my_class);
        unregister_chrdev_region(my_dev.dev_number, 1);
        return -1;
    }


        printk("spi device mode set  mode  speed soON .\n");
        printk("do  spi_setup   SPI_MODE_1 .\n");
        my_dev.spi_dev->mode = SPI_MODE_1;        /* mode 1表示:空闲的时候是低电平,在下降沿采样(第二个沿) */

        //可以打印下--看看maxhz是不是从设备树中取出来
        printk("only  look my_dev.spi_dev->max_speed_hz = %d .\n", my_dev.spi_dev->max_speed_hz );
       
        my_dev.spi_dev->max_speed_hz = 3000000;
        printk("my_dev.spi_dev->max_speed_hz = 3000000 .\n ");
       
        printk("my_dev.spi_dev->cs_gpio = %d .\n", my_dev.spi_dev->cs_gpio );
       
        spi_setup( my_dev.spi_dev );


        //把配置寄存器的操作写到这里
        printk("set the config register . \n");
        {
                int ret = -1;
                //unsigned char txdata[8];
                //unsigned char rxdata[8];

                struct spi_transfer transfer  = {0} ;//内部没有做初始化---        unsigned        cs_change:1; 只是站位
                struct spi_message         msg = {0} ;
               
                dma_addr_t  tx_dma = 0;
                dma_addr_t  rx_dma = 0;

                if (dma_set_coherent_mask(  &(my_dev.spi_dev->dev) , DMA_BIT_MASK(32)))
                {
                        printk("dma_set_coherent_mask  error . \n");
                        return -1;
                }

                unsigned char *txdata = dma_alloc_coherent( &(my_dev.spi_dev->dev), 256, &tx_dma, GFP_KERNEL);
                   unsigned char *rxdata = dma_alloc_coherent( &(my_dev.spi_dev->dev), 256, &rx_dma, GFP_KERNEL);
               
                if( (txdata == 0)||(rxdata == 0) )
                {
                        printk("dma_alloc_coherent error . \n");
                        return -1;
                }
                else
                {
                        printk("dma_alloc_coherent ok . \n");
                }
               
               
                //=================================================================1
                //SPI Single-Byte Write  单次写模式--2字节写完后cs会拉高
                txdata[0] = 0x80;//要写的寄存器地址 --最高位为1
                txdata[1] = 0xd1;//0x00寄存器要写的值

                transfer.tx_buf = txdata;
                transfer.rx_buf = rxdata;
               
                transfer.tx_dma = tx_dma;
                transfer.len = 2;//2个字节
                transfer.delay_usecs = 10;


                msg.is_dma_mapped = 1;       
                spi_message_init( &msg );
                spi_message_add_tail( &transfer ,   &msg );

                msg.is_dma_mapped = 1;       
                printk("msg.is_dma_mapped = %d .\n", msg.is_dma_mapped );
                 
               
                ret = spi_sync( my_dev.spi_dev , &msg );        /* 同步发送 */
            if(ret ==0 )
            {
                    printk("if(ret ==0 )   configute reg  0xd1  write ok. \n");
            }
            else
            {
                    printk("configute reg  write error. \n");
            }
               



                //测试--再读取回来试试
                //SPI Single-Byte read  单次写模式--2字节写完后cs会拉高
                transfer.tx_buf = txdata;
                transfer.rx_buf = rxdata;
               
                txdata[0] = 0x00;//要读的寄存器地址 --最高位为0
                transfer.tx_dma = tx_dma;
                transfer.len = 2;//2个字节
                transfer.delay_usecs = 10;
               
                rxdata[0]=0;
                rxdata[1]=0;
                transfer.rx_dma = rx_dma;


               
                msg.is_dma_mapped = 1;               
                spi_message_init( &msg );
                spi_message_add_tail( &transfer ,   &msg );

                msg.is_dma_mapped = 1;
                printk("msg.is_dma_mapped = %d .\n", msg.is_dma_mapped );
                 

                ret = spi_sync( my_dev.spi_dev , &msg );        /* 同步发送 */
            if(ret ==0 )
            {
                    printk("if(ret ==0 )   configute reg  read ok.   \n");
                    printk("rxdata[1] = 0x%x .\n", rxdata[1] );
            }
            else
            {
                    printk("configute reg  read error. \n");
            }       
               
            printk("my_device_init  dma_free_coherent .\n");
                dma_free_coherent(  &(my_dev.spi_dev->dev), 256, txdata , tx_dma );
                dma_free_coherent(  &(my_dev.spi_dev->dev), 256, rxdata , rx_dma );
        }
       

    printk(KERN_INFO " My device module loaded.  spi  2024-3-30. \n");
       
    return 0;

}


static void   my_device_exit(void)
{
        printk("my_device_exit .\r\n");
       
    cdev_del(&my_dev.my_cdev);
    unregister_chrdev_region(my_dev.dev_number, 1);

    device_destroy(my_dev.my_class, my_dev.dev_number);
    class_destroy(my_dev.my_class);

    printk("My device module unloaded  .spi  . \n");
}




       








//===================================================================================================
//spi 相关的---是spicore框架--属于外层的皮==最终spi_device作为链接中心对自己创建的节点提供数据通道服务
static int max31865_probe(struct spi_device *spi)
{
    struct spi_device *spi_dev;
    int ret;

    my_dev.spi_dev = spi; //保存起来--最终整个大的结构体都放到私有指针上

    printk("MAX31865 driver probed  .\n");

    printk("name=alientek,max31865  match ok  .\n");

       
       
        //创建自己的驱动节点
        printk("create my self devNode . \n");

        my_device_init();

       
       
    return 0;

}

static int max31865_remove(struct spi_device *spi)
{
        printk("max31865_remove . \n");
         
        my_device_exit();
       
    my_dev.spi_dev = NULL;


       
    //释放自己的驱动节点
        printk("delete my self devNode . \n");
       
    return 0;
}





//外层包裹的spi皮
static struct of_device_id id_table[] =
{
        { .compatible = "test,max31865" },
        { }
};


static struct spi_driver max31865_driver =
{
    .probe = max31865_probe,
    .remove = max31865_remove,
    .driver =
    {
        .name  = "max31865Sensor",  //这是名字-不是用于匹配的==兼容字段compatible才是
        .owner = THIS_MODULE,
        .of_match_table = id_table, //match 名字
    }
};





static int __init max31865_init(void)
{
        printk("max31865_init   dma method . \n");
        printk("spi_register_driver . \n");
    return spi_register_driver(&max31865_driver);
}

static void __exit max31865_exit(void)
{
        printk("max31865_exit . \n");
        printk("spi_unregister_driver . \n");
       
    spi_unregister_driver(&max31865_driver);
}


module_init(max31865_init);
module_exit(max31865_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR(" make");
MODULE_DESCRIPTION("A simple example of spi driver");


把  transfer.tx_buf = txdata;
                transfer.rx_buf = rxdata; 都去掉也不行

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

1

主题

4

帖子

0

精华

初级会员

Rank: 2

积分
75
金钱
75
注册时间
2020-5-24
在线时间
33 小时
发表于 2024-11-6 16:01:47 | 显示全部楼层
回复

使用道具 举报

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

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-22 05:32

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表