初级会员
- 积分
- 123
- 金钱
- 123
- 注册时间
- 2016-9-5
- 在线时间
- 21 小时
|
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; 都去掉也不行
|
|