linux3.2下adt7320的spi驱动编写
2015-08-07 16:00
531 查看
在3.2中没有spi_read/spi_write, 更改为了spi_write_then_read, 好用惨了
驱动程序adt7320_driver.c
测试程序adt7320.c
驱动程序adt7320_driver.c
#include <linux/init.h> #include <linux/module.h> #include <linux/ioctl.h> #include <linux/fs.h> #include <linux/device.h> #include <linux/err.h> #include <linux/list.h> #include <linux/errno.h> #include <linux/mutex.h> #include <linux/slab.h> #include <linux/compat.h> #include <linux/spi/spi.h> #include <linux/spi/spidev.h> #include <asm/uaccess.h> #define Contin_Mode 0x00 #define OneShot_Mode 0x01 #define SPS1_Mode 0x02 #define ShutDown_Mode 0x03 #define Bit16_Mode 1 #define Bit13_Mode 0 #define CMDREAD 1 #define CMDWRITE 0 #define STATUS_REG 0x00 #define CONFIG_REG 0x01 #define TEMPVAL_REG 0x02 #define ID_REG 0x03 #define TCRIT_REG 0x04 #define THYST_REG 0x05 #define THIGH_REG 0x06 #define TLOW_REG 0x07 #define Dummy_Byte 0x5A #define INIT 0x1 #define RESET 0x0 #define SPIDEV_MAJOR 153 static struct class *adt7320_class; static struct spi_device *adt7320_spi_device; static char rx_buf[5] = {0}, tx_buf[5] = {0}; /* adt7301 adt7302 adt7310 adt7316 */ /******************************************************************************* * Function Name : Reg_Select * Description : 选中 adt7320 的寄存器, 指定操作读或写 * Input : operate: 0 读 / 1 写, val 寄存器编号 * Return : None *******************************************************************************/ unsigned char Reg_Select(unsigned char operate, unsigned char val) { unsigned char cmd = 0; if (operate)//bit7: 1 读 , 0 写 { cmd |= (1 << 6); } else { cmd &= ~(1 << 6); } cmd |= (val << 3); cmd &= ~((1<<7) | (1<<2) | (1<<1) | (1<<0)); return cmd; } /******************************************************************************* * desc: get temperature from adt7320 *******************************************************************************/ static ssize_t adt7320_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) { int ret = 0; int adcVal = 0; float tempVal = 0; tx_buf[0] = Reg_Select(CMDREAD, TEMPVAL_REG); spi_write_then_read(adt7320_spi_device, tx_buf, 1, rx_buf, 2); adcVal = (rx_buf[0] << 8) + rx_buf[1]; ret = copy_to_user(&adcVal, buf, sizeof(float)); return ret; } static unsigned char getID(void) { tx_buf[0] = Reg_Select(CMDREAD, ID_REG); spi_write_then_read(adt7320_spi_device, tx_buf, 1, rx_buf, 1); return rx_buf[0]; } /******************************************************************************* * desc: read chip_id, if chip_id equals to 0xC3 , chip initail success * return: chip initail success return 0, else return -1 *******************************************************************************/ static int Init(void) { unsigned char chip_id = 0; chip_id = getID(); if (chip_id == 0xC3) { printk ("init success\n"); return 0; } else { printk ("init failed\n"); return -1; } } //adt7320 reset by 4 byte '0xFF' static void Reset(void) { tx_buf[0] = 0xFF; tx_buf[1] = 0xFF; tx_buf[2] = 0xFF; tx_buf[3] = 0xFF; spi_write_then_read(adt7320_spi_device, tx_buf, 4, rx_buf, 0); } static long adt7320_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { switch (cmd ) { case INIT: Init(); break; case RESET: Reset(); break; default:break; } printk ("adt7320 ioctl\n"); return 0; } static int adt7320_open(struct inode *inode, struct file *filp) { printk ("adt7320 open!\n"); return 0; } static int adt7320_release(struct inode *inode, struct file *filp) { printk ("adt7320 release!\n"); return 0; } static struct file_operations adt7320_fops = { .owner = THIS_MODULE, .open = adt7320_open, .read = adt7320_read, .unlocked_ioctl = adt7320_ioctl, .release = adt7320_release, }; /* * desc: ÔÚprobeÖд´½¨É豸 * device_create * */ static int __devinit adt7320_probe(struct spi_device *spi) { adt7320_spi_device = spi; device_create(adt7320_class, NULL, MKDEV(SPIDEV_MAJOR, 0), NULL, "adt7320"); return 0; } /* *desc: ÔÚremoveÖÐ×¢ÏúÉ豸 * device_destroy * */ static int __devexit adt7320_remove(struct spi_device *spi) { device_destroy(adt7320_class, MKDEV(SPIDEV_MAJOR, 0)); return 0; } static struct spi_driver adt7320_driver = { .driver = { .name = "adt7320", .owner = THIS_MODULE, }, .probe = adt7320_probe, .remove = __devexit_p(adt7320_remove), }; static int adt7320_init(void) { register_chrdev(SPIDEV_MAJOR, "spi_temp", &adt7320_fops); adt7320_class = class_create(THIS_MODULE, "adt7320_class"); spi_register_driver(&adt7320_driver); return 0; } static void adt7320_exit(void) { spi_unregister_driver(&adt7320_driver); class_destroy(adt7320_class); unregister_chrdev(SPIDEV_MAJOR, "spi_temp"); } module_init(adt7320_init); module_exit(adt7320_exit); MODULE_LICENSE("GPL");因为编译为模块添加到内核总是提示函数未定义, 只好将它添加到内核里了. (kernel)/driver/spi/Makefile 中在 spidev.o 后添加 adt7320_driver.o 重新编译内核即可.
测试程序adt7320.c
#include <stdint.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <getopt.h> #include <fcntl.h> #include <sys/ioctl.h> #define INIT 0x1 #define RESET 0x0 static const char *device = "/dev/adt7320"; static void pabort(const char *s) { perror(s); abort(); } int main(int argc, char const *argv[]) { float tempVal = 0; int adcVal = 0; int fd = 0; fd = open(device, O_RDWR); if (fd < 0) { pabort("can not open device"); } ioctl(fd, RESET); ioctl(fd, INIT); while(1) { read(fd, &adcVal, sizeof(int)); tempVal = (float)(adcVal >> 3); //低3位为标志位 if (adcVal & 0x8000) //最高位为1则为负值 { tempVal = (tempVal - 8192) / 16.0; } else { tempVal = tempVal / 16.0; } printf ("temperature: %f C\n", tempVal); sleep (1); } close(fd); return 0; }另外内核里不能使用浮点数, 只能将adc的值返回到用户空间, 再换算为温度值
相关文章推荐
- Linux - sed 工具
- Linux - sed 工具
- centos 配置本地yum源
- Linux进程间通信方式--信号,管道,消息队列,信号量,共享内存
- linux lsof详解
- Linux 编译器之 GCC
- Linux 常用编辑器之vim
- Linux基础正则表达式字符汇整(characters)
- Linux基础正则表达式字符汇整(characters)
- Linux 常用命令的使用
- Linux 文件权限简单说明
- Linux 目录结构及文件
- 换一种方式创建Linux下的自解压文件
- Ubuntu:14.04.2 安装多个Linux内核
- linux下svn的常用指令
- Linux必备软件之SSH
- Ubuntu Amarok 安装及几个常见问题解决
- 如何在Linux下安装Erlang
- ARM Linux系统的时钟机制
- centOS简单优化