linux3.2下adt7320的spi驱动编写

来源:互联网 发布:串口数据采集软件 编辑:程序博客网 时间:2024/05/16 15:36

在3.2中没有spi_read/spi_write, 更改为了spi_write_then_read, 好用惨了

驱动程序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 153static struct class *adt7320_class;static struct spi_device *adt7320_spi_device;static char rx_buf[5] = {0}, tx_buf[5] = {0};/*adt7301 adt7302adt7310adt7316*//******************************************************************************** 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  0x0static 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的值返回到用户空间, 再换算为温度值

0 0
原创粉丝点击