参考资料:用户态调用spidev操作DAC模块
一、修改设备树
&spi0 {
dac:dac@00{
compatible = "100ask,dac";
reg = <0>;
spi-max-frequency = <10000000>;
status="okay";
};
};
二、编写驱动程序
#include <linux/init.h>
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <asm/uaccess.h>
#include <linux/device.h>
#include <linux/of.h>
static struct spi_device *dac;
static int major;
static long
spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int val;
int err;
int old_val = 0;
unsigned char tx_buf[2];
unsigned char rx_buf[2];
struct spi_message msg;
struct spi_transfer xfer[1];
int status;
memset(&xfer[0], 0, sizeof(xfer));
err = copy_from_user(&val, (const void __user *)arg, sizeof(int));
printk(KERN_ERR"copy from user %d \n", val);
val <<= 2;
val &= 0xFFC; //只发送8位
tx_buf[0] = (val>>8) & 0xff; //低位在前
tx_buf[1] = val & 0xff;
xfer[0].tx_buf = tx_buf;
xfer[0].rx_buf = rx_buf;
xfer[0].len = 2;
spi_message_init(&msg);
spi_message_add_tail(&xfer[0], &msg);
status = spi_sync(dac, &msg);
printk(KERN_ERR"spi_sync %d \n", status);
old_val = (rx_buf[0]<<8) | (rx_buf[1]); //把读到的数据返回给应用层
old_val >>= 2;
err = copy_to_user((void __user*)arg, &old_val, sizeof(int));
return 0;
}
static const struct file_operations spidev_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = spidev_ioctl,
};
static struct class *spidev_class;
static const struct of_device_id spidev_dt_ids[] = {
{ .compatible = "100ask,dac" },
{},
};
static int spidev_probe(struct spi_device *spi)
{
dac = spi;
major = register_chrdev(0, "100ask_dac", &spidev_fops);
spidev_class = class_create(THIS_MODULE, "100ask_dac");
device_create(spidev_class, NULL, MKDEV(major, 0), NULL, "100ask_dac");
return 0;
}
static int spidev_remove(struct spi_device *spi)
{
device_destroy(spidev_class, MKDEV(major, 0));
class_destroy(spidev_class);
unregister_chrdev(major, "100ask_dac");
return 0;
}
static struct spi_driver spidev_spi_driver = {
.driver = {
.name = "100ask_spi_dac_drv",
.of_match_table = of_match_ptr(spidev_dt_ids),
},
.probe = spidev_probe,
.remove = spidev_remove,
};
static int __init spidev_init(void)
{
int status;
status = spi_register_driver(&spidev_spi_driver);
if(status < 0) {
printk(KERN_ERR"spidev_spi_driver error\n");
}
return status;
}
module_init(spidev_init);
static void __exit spidev_exit(void)
{
spi_unregister_driver(&spidev_spi_driver);
}
module_exit(spidev_exit);
MODULE_LICENSE("GPL");
三、编写应用程序
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/types.h>
#define SPI_IOC_WR 123
int main(int argc, char **argv)
{
int fd;
unsigned int val;
int status;
unsigned char tx_buf[2];
unsigned char rx_buf[2];
if(argc != 3) {
printf("Usage: %s /dev/100ask_dac <val>\n", argv[0]);
return 0;
}
fd = open(argv[1], O_RDWR);
if(fd < 0) {
printf("can not open %s\n", argv[1]);
return 1;
}
val = strtoul(argv[2], NULL, 0);
status = ioctl(fd, SPI_IOC_WR, &val);
if(status < 0) {
printf("SPI_IOC_WR\n");
return -1;
}
printf("Pre val = %d\n", val);
return 0;
}
四、操作过程和结果
[root@firefly-rk3288:/home/picture/spi/dac_drv]# insmod dac_drv.ko
[ 456.955496] dac_drv: loading out-of-tree module taints kernel.
[root@firefly-rk3288:/home/picture/spi/dac_drv]# ./dac_test /dev/
100ask_dac loop2 stderr tty33 tty61
ashmem loop3 stdin tty34 tty62
block/ loop4 stdout tty35 tty63
bus/ loop5 tty tty36 tty7
char/ loop6 tty0 tty37 tty8
console loop7 tty1 tty38 tty9
cpu_dma_latency mali0 tty10 tty39 ttyFIQ0
dht11 mapper/ tty11 tty4 ttyS0
disk/ mem tty12 tty40 ttyS1
dri/ memory_bandwidth tty13 tty41 ttyS2
ds18b20 mmcblk0 tty14 tty42 ttyS3
fb0 mmcblk0p1 tty15 tty43 ttyS4
fd/ mmcblk0p2 tty16 tty44 uhid
full mmcblk2 tty17 tty45 uinput
fuse mmcblk2boot0 tty18 tty46 urandom
hdmi_hdcp1x mmcblk2boot1 tty19 tty47 usbmon0
hevc-service mmcblk2rpmb tty2 tty48 usbmon1
hwrng net/ tty20 tty49 usbmon2
i2c-0 network_latency tty21 tty5 usbmon3
i2c-2 network_throughput tty22 tty50 usbmon4
i2c-3 null tty23 tty51 v4l/
i2c-4 ppp tty24 tty52 vcs
i2c-6 ptmx tty25 tty53 vcs1
iio:device0 pts/ tty26 tty54 vcsa
input/ ram0 tty27 tty55 vcsa1
irda random tty28 tty56 vendor_storage
kmsg rfkill tty29 tty57 vhci
log rtc tty3 tty58 video0
loop-control rtc0 tty30 tty59 vpu-service
loop0 shm/ tty31 tty6 zero
loop1 snd/ tty32 tty60 zram0
[root@firefly-rk3288:/home/picture/spi/dac_drv]# ./dac_test /dev/100ask_dac 0
[ 472.618281] copy from user 0
[ 472.622078] spi_sync 0
Pre val = 0
[root@firefly-rk3288:/home/picture/spi/dac_drv]# ./dac_test /dev/100ask_dac 500
[ 475.983460] copy from user 500
[ 475.987103] spi_sync 0
Pre val = 0
[root@firefly-rk3288:/home/picture/spi/dac_drv]# ./dac_test /dev/100ask_dac 1000
[ 479.009154] copy from user 1000
[ 479.013211] spi_sync 0
Pre val = 500
[root@firefly-rk3288:/home/picture/spi/dac_drv]# ./dac_test /dev/100ask_dac 200
[ 482.198009] copy from user 200
[ 482.201851] spi_sync 0
Pre val = 1000
[root@firefly-rk3288:/home/picture/spi/dac_drv]# ./dac_test /dev/100ask_dac 300
[ 484.559005] copy from user 300
[ 484.562844] spi_sync 0
Pre val = 200
[root@firefly-rk3288:/home/picture/spi/dac_drv]# ./dac_test /dev/100ask_dac 400
[ 486.566507] copy from user 400
[ 486.570157] spi_sync 0
Pre val = 300
[root@firefly-rk3288:/home/picture/spi/dac_drv]# ./dac_test /dev/100ask_dac 500
[ 489.214435] copy from user 500
[ 489.218095] spi_sync 0
Pre val = 400
[root@firefly-rk3288:/home/picture/spi/dac_drv]#