1. 程式人生 > >linux3.2下adt7320的spi驅動編寫

linux3.2下adt7320的spi驅動編寫

在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的值返回到使用者空間, 再換算為溫度值

相關推薦

linux3.2adt7320的spi驅動編寫

在3.2中沒有spi_read/spi_write, 更改為了spi_write_then_read, 好用慘了 驅動程式adt7320_driver.c #include <linux/init.h> #include <linux/module.h&g

linux3.5I2C驅動

                        &

linux3.5I2C驅動

                知識背景: 1. I2C協議 2. 4412處理器I2C介面說明 3. bus-dev-drv模型(詳見文章-Linux下驅動:分層、分離機制學習筆記) 4. linux核心下驅動設計基本知識 一、驅動框架       以4412+linux3.5平臺為例,說明Linu

Linuxnorflash驅動編寫方法

                                                                      Linux下norflash驅動編寫步驟 1. 分配map_info結構體 2. 設定: 物理基地址(phys), 大小(size),

在虛擬機器Ubuntu進行簡單的ko驅動編寫問題處理

主要就是編寫了驅動模組Helloko(hello.c 、Makefile) & 測試應用程式(hellotest.c) hello.c:   makefile: hellotest.c: step1: make   先生成k

vxWorks6.6基於VxBus架構的Can控制器(sja1000t)驅動編寫

vxWorks6.6下基於VxBus架構的Can控制器驅動編寫 1       VxBus下驅動的架構 Workbench3.0是VxWorks 6.x 的整合開發環境,而VxWorks 5.5是採用Tornado2.2 來進行開發的。Workbench3.

最佳程序設計探索之一 需求驅動編寫自頂向的代碼

敏捷 sage auth 可以登錄 ron 代碼 驅動 時序 inf 寫一段文字描述程序要完成什麽樣的功能,然後將這段文字的名詞轉換成類或者類的屬性,將動詞轉換成類的方法。這是80年代中期的經典做法。 <<設計模式解析>> 2nd 開篇

Linuxspi驅動開發(2

Linux下spi驅動開發之m25p10驅動測試 目標:在華清遠見的FS_S5PC100平臺上編寫一個簡單的spi驅動模組,在probe階段實現對m25p10的ID號探測、flash擦除、flash狀態讀取、flash寫入、flash讀取等操作。程式碼已經經過測試,運行於

關於樹莓派核心編譯和驅動編寫(2)

前幾天搞定了樹莓派2的核心編譯執行工作,這幾天集中研究了樹莓派的gpio操作,那麼現在是時候把它搞出來了 我們知道,gpio操作是驅動的基礎操作,那麼研究一塊板子,一個版本的核心,首先要從gpio入手。 基礎的gpio操作有以下: ioremap對映暫存器地址,readl

IMX6平臺Linux3.14.28系統編譯驅動模組ko和應用程式的Makefile模版

obj-m += button.oARCH=armMYCROSS_COMPILE=/opt/poky/1.7/sysroots/x86_64-pokysdk-linux/usr/bin/arm-poky-linux-gnueabi/arm-poky-linux-gnueabi

CentOS7.2unison+inotify的Web目錄同步方案

web 同步 unison inotify CentOS7.2下unison+inotify的Web目錄同步方案學習 unisonCentOS7.2下unison+inotify的Web目錄同步方案1. 背景2. Unison簡介3. 環境準備4. 安裝Objective Caml compi

Laravel5.2隊列驅動expire參數設置帶來的重復執行問題 數據庫驅動

laravel php 隊列 ‘connections‘ => [ .... ‘database‘ => [ ‘driver‘ => ‘database‘, ‘table‘ => ‘jobs‘,

SylixOSIIS驅動編程

飛利浦公司 示意圖 音頻驅動 接口 開發 目錄1. IIS簡介 12. 數字聲音簡介 12.1 采樣頻率 12.2 量化位數 12.3 聲道數 13. WAV音頻文件格式簡介 23.1 文件格式 23.2 原始聲音數據

linux驅動編寫之中斷處理

類型 div 應該 urn 處理方式 com pre turn 申請 一、中斷 1、概念 學過單片機的應該非常清楚中斷的概念,也就是CPU在正常執行程序過程中,出現了突發事件(中斷事件),於是CPU暫停當前程序的執行,轉去處理突發事件。處理完畢後,CPU又返回被

CentOS 7.2安裝Mono 5.0

nbsp 很好 all win ack style 領域 logs 平臺 微軟Build2017大會期間.NET領域的.NET core之外,就是Visual Studio For Mac,大家都知道Visual Studio For Mac 是基於Mono運行的,Mono

cocos2d-x3.2 使用多線程

lan ont trac false main 下使用 cpp pub .cpp 事實上在cocos2dx下使用多線程事實上就是用C++去寫,這裏提供幾個簡單的樣例: 原文地址:http://blog.csdn.net/qqmcy/article/details/362

centos 7.2 為erlang添加protobuffs

per 代碼 brush 協議 讀取 ger required mpi 會有 安裝前提: 1.已經安裝好erlang otp 2.配置了rebar (配置方法:http://www.cnblogs.com/panfeng412/archive/2011/08/14/2

Centos7.2部署Java開發環境

$path 2.x ava x64 jdk server telnet 選擇 new 1.安裝JDK   如果以前安裝過JDK,想要重新安裝可執行如下命令進行卸載,這裏安裝的是JDK1.8:   先查詢: rpm -qa|grep jdk   然後再通過下面命令進行卸載

VirtualBox+ubuntu-16.04.2 NAT+Host-only網絡配置

配置文件 mas 沒有 net 情況 win 網絡配置 add host-only VirtualBox 5.1.20 ubuntu-16.04.2服務器版。 主要用於工作編譯,虛擬機放在後臺跑。windows下ssl登錄。占用資源少。配置虛擬機網絡為NAT+Host-on

CentOS7.2一鍵安裝Openstack

centos7.2下一鍵安裝openstackCentOS7.2下一鍵安裝Openstack 系統環境:Oracle VirtualBox 4.38CentOS-7.2-x86_64-bin-DVD1.iso 安裝前需要修改 /etc/hosts文件,添加 127.0.0.1 dev-100 (dev-100