您的位置:首页 > 运维架构 > Linux

linux3.2下adt7320的spi驱动编写

2015-08-07 16:00 531 查看
在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 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的值返回到用户空间, 再换算为温度值
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: