• 正文
    • 一、修改設(shè)備樹
    • 二、編寫icm20607.c驅(qū)動
    • 三、完整驅(qū)動icm20607.c示例源碼
    • 四、編譯
    • 五、編寫測試源碼icm20607_app.c
    • 六、編譯應(yīng)用
    • 七、測試
  • 相關(guān)推薦
申請入駐 產(chǎn)業(yè)圖譜

飛凌嵌入式ElfBoard ELF 1板卡-六軸傳感器驅(qū)動

4小時前
166
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點資訊討論

例程代碼路徑:ELF 1開發(fā)板資料包3-例程源碼3-2 驅(qū)動例程源碼9_Regmap-icm20607

下面編寫一個六軸傳感器的驅(qū)動,來了解Regmap子系統(tǒng)的具體使用。

一、修改設(shè)備樹

(一)查看原理圖引腳復(fù)用表格,確定六軸傳感器連接引腳。

(二)在設(shè)備樹文件arch/arm/boot/dts/imx6ull-elf1-emmc.dts的IOMUX節(jié)點下添加子節(jié)點:

pinctrl_ecspi1: ecspi1grp {

fsl,pins = <

MX6UL_PAD_LCD_DATA20__ECSPI1_SCLK ??????0x10b0

MX6UL_PAD_LCD_DATA21__GPIO3_IO26 ????????0x10b0

MX6UL_PAD_LCD_DATA22__ECSPI1_MOSI ??????0x10b0

MX6UL_PAD_LCD_DATA23__ECSPI1_MISO ??????0x10b0

>;

};

添加后效果如下:

在arch/arm/boot/dts/imx6ull-elf1-emmc.dts文件中搜索引腳PAD NAME,在&iomux的子節(jié)點pinctrl_lcdif_dat節(jié)點下搜索到了這幾個引腳的復(fù)用,我們需要將這些注釋掉:

(三)添加設(shè)備節(jié)點

在arch/arm/boot/dts/imx6ull.dtsi中已經(jīng)存在了spi接口的相關(guān)節(jié)點ecspi1-ecspi4,我們只需要在arch/arm/boot/dts/imx6ull-elf1-emmc.dts文件中引用相關(guān)節(jié)點,并在該節(jié)點下添加子節(jié)點spidevicm:

&ecspi1 {

pinctrl-names = "default";

pinctrl-0 = <&pinctrl_ecspi1>;

fsl,spi-num-chipselects = <1>;

cs-gpios = <&gpio3 26 GPIO_ACTIVE_LOW>;

status = "okay";

spidevicm: icm20607@0 {

compatible = "icm20607";

spi-max-frequency = <8000000>;

reg = <0>;

};

};

添加后的效果如下:

(四)重新編譯設(shè)備樹,用7.9.4.2節(jié)編譯好的內(nèi)核即可:

. /opt/fsl-imx-x11/4.1.15-2.0.0/environment-setup-cortexa7hf-neon-poky-linux-gnueabi

elf@ubuntu:~/work/linux-imx-imx_4.1.15_2.0.0_ga$ make dtbs

編譯生成的設(shè)備樹文件為imx6ull-elf1-emmc.dtb,參考《01-0 ELF1、ELF1S開發(fā)板_快速啟動手冊_V1》4.4節(jié)單獨更新設(shè)備樹。

二、編寫icm20607.c驅(qū)動

(一)在驅(qū)動中要操作很多芯片相關(guān)的寄存器,所以需要先新建一個icm20607.h的頭文件,用來定義相關(guān)寄存器值。

#ifndef ICM20607_H

#define ICM20607_H

/***************************************************************

文件名 : icm20607.h

描述 : ICM20607寄存器地址描述頭文件

***************************************************************/

#define ICM20608G_ID 0XAF /* ID值 */

#define ICM20608D_ID 0XAE /* ID值 */

#define ICM20607_ID 0X05

/* ICM20607寄存器

*復(fù)位后所有寄存器地址都為0,除了

*Register 107(0x41) Power Management 1

*Register 117(0x05) WHO_AM_I

*Register 26(0x80) CONFIG

*/

/* 陀螺儀和加速度自測(出產(chǎn)時設(shè)置,用于與用戶的自檢輸出值比較) */

/* ICM20607 SELF TEST GYRO Modify 0x ->5x */

#define ICM20_SELF_TEST_X_GYRO 0x50

#define ICM20_SELF_TEST_Y_GYRO 0x51

#define ICM20_SELF_TEST_Z_GYRO 0x52

#define ICM20_SELF_TEST_X_ACCEL 0x0D

#define ICM20_SELF_TEST_Y_ACCEL 0x0E

#define ICM20_SELF_TEST_Z_ACCEL 0x0F

/* 陀螺儀靜態(tài)偏移 */

#define ICM20_XG_OFFS_USRH 0x13

#define ICM20_XG_OFFS_USRL 0x14

#define ICM20_YG_OFFS_USRH 0x15

#define ICM20_YG_OFFS_USRL 0x16

#define ICM20_ZG_OFFS_USRH 0x17

#define ICM20_ZG_OFFS_USRL 0x18

#define ICM20_SMPLRT_DIV 0x19

#define ICM20_CONFIG 0x1A

#define ICM20_GYRO_CONFIG 0x1B

#define ICM20_ACCEL_CONFIG 0x1C

#define ICM20_ACCEL_CONFIG2 0x1D

#define ICM20_LP_MODE_CFG 0x1E

#define ICM20_ACCEL_WOM_THR 0x1F

#define ICM20_FIFO_EN 0x23

#define ICM20_FSYNC_INT 0x36

#define ICM20_INT_PIN_CFG 0x37

#define ICM20_INT_ENABLE 0x38

#define ICM20_INT_STATUS 0x3A

/* 加速度輸出 */

#define ICM20_ACCEL_XOUT_H 0x3B

#define ICM20_ACCEL_XOUT_L 0x3C

#define ICM20_ACCEL_YOUT_H 0x3D

#define ICM20_ACCEL_YOUT_L 0x3E

#define ICM20_ACCEL_ZOUT_H 0x3F

#define ICM20_ACCEL_ZOUT_L 0x40

/* 溫度輸出 */

#define ICM20_TEMP_OUT_H 0x41

#define ICM20_TEMP_OUT_L 0x42

/* 陀螺儀輸出 */

#define ICM20_GYRO_XOUT_H 0x43

#define ICM20_GYRO_XOUT_L 0x44

#define ICM20_GYRO_YOUT_H 0x45

#define ICM20_GYRO_YOUT_L 0x46

#define ICM20_GYRO_ZOUT_H 0x47

#define ICM20_GYRO_ZOUT_L 0x48

#define ICM20_SIGNAL_PATH_RESET 0x68

#define ICM20_ACCEL_INTEL_CTRL 0x69

#define ICM20_USER_CTRL 0x6A

#define ICM20_PWR_MGMT_1 0x6B

#define ICM20_PWR_MGMT_2 0x6C

#define ICM20_FIFO_COUNTH 0x72

#define ICM20_FIFO_COUNTL 0x73

#define ICM20_FIFO_R_W 0x74

#define ICM20_WHO_AM_I 0x75

/* 加速度靜態(tài)偏移 */

#define ICM20_XA_OFFSET_H 0x77

#define ICM20_XA_OFFSET_L 0x78

#define ICM20_YA_OFFSET_H 0x7A

#define ICM20_YA_OFFSET_L 0x7B

#define ICM20_ZA_OFFSET_H 0x7D

#define ICM20_ZA_OFFSET_L 0x7E

#endif

(二)icm20607.c文件編寫

(1)頭文件引用

#include <linux/module.h>

#include <linux/init.h>

#include <linux/fs.h> ??????????// 包含文件系統(tǒng)相關(guān)函數(shù)的頭文件

#include <linux/uaccess.h> ?????// 包含用戶空間數(shù)據(jù)訪問函數(shù)的頭文件

#include <linux/cdev.h> ????????//包含字符設(shè)備頭文件

#include <linux/device.h>

#include <linux/delay.h>

#include <linux/spi/spi.h>

#include <linux/regmap.h>

#include <linux/of.h>

#include <linux/of_address.h>

#include <linux/of_gpio.h>

#include "icm20607.h"

(2)創(chuàng)建相關(guān)宏定義和變量

#define ICM20607_REG_WHOAMI ?????0x75

#define ICM20607_WHOAMI_VALUE ???0xAF

#define DEVICE_NAME "icm20607" ?// 設(shè)備名稱

static dev_t dev_num; ??//分配的設(shè)備號

int major; ?//主設(shè)備號

int minor; ?//次設(shè)備號

struct icm20607_dev {

struct spi_device *spi_dev; /* spi設(shè)備 */

dev_t dev_num; /* 設(shè)備號 ?*/

struct cdev cdev; /* cdev */

struct class *class; /* 類 */

struct device *device; /* 設(shè)備 ?*/

struct device_node *nd; /* 設(shè)備節(jié)點 */

int cs_gpio; /* 片選所使用的GPIO編號 */

signed int gyro_x_adc; /* 陀螺儀X軸原始值 ?*/

signed int gyro_y_adc; /* 陀螺儀Y軸原始值 */

signed int gyro_z_adc; /* 陀螺儀Z軸原始值 */

signed int accel_x_adc; /* 加速度計X軸原始值 */

signed int accel_y_adc; /* 加速度計Y軸原始值 */

signed int accel_z_adc; /* 加速度計Z軸原始值 */

signed int temp_adc; /* 溫度原始值 */

struct regmap *spi_regmap; /* regmap */

struct regmap_config regmap_config;

};

(3)驅(qū)動模塊的入口和出口

module_init(icm20607_init);

module_exit(icm20607_exit);

(4)icm20607_init和icm20607_exit實現(xiàn)

static int __init icm20607_init(void)

{

int ret;

ret = spi_register_driver(&icm20607_driver);

if (ret < 0) {

pr_err("Failed to register ICM20607 driver: %dn", ret);

return ret;

}

pr_info("ICM20607 SPI device driver loadedn");

return 0;

}

static void __exit icm20607_exit(void)

{

spi_unregister_driver(&icm20607_driver);

pr_info("ICM20607 SPI device driver unloadedn");

}

在入口函數(shù)中調(diào)用了spi_register_driver函數(shù),來注冊SPI總線驅(qū)動程序。在出口函數(shù)中調(diào)用了spi_unregister_driver函數(shù),來注銷驅(qū)動程序。

spi_register_driver函數(shù)原型如下:

int spi_register_driver(struct spi_driver *drv);

該函數(shù)接受一個指向struct spi_driver結(jié)構(gòu)體的指針作為參數(shù),并返回一個整數(shù)值,表示注冊是否成功。struct spi_driver結(jié)構(gòu)體定義了SPI總線驅(qū)動程序的屬性和回調(diào)函數(shù)。

以下是struct spi_driver結(jié)構(gòu)體的常見成員:

driver:struct device_driver類型的成員,描述了驅(qū)動程序的基本信息,如名稱、總線類型等。

probe:指向驅(qū)動程序的探測函數(shù)的指針。探測函數(shù)在與設(shè)備匹配時被調(diào)用,用于初始化設(shè)備并注冊相關(guān)資源。

remove:指向驅(qū)動程序的移除函數(shù)的指針。移除函數(shù)在設(shè)備被卸載時被調(diào)用,用于清理和釋放相關(guān)資源。

id_table:指向struct spi_device_id數(shù)組的指針,用于匹配驅(qū)動程序和設(shè)備之間的關(guān)聯(lián)關(guān)系。

probe_new:指向新版的探測函數(shù)的指針。新版探測函數(shù)支持更多功能,并可以替代舊版的probe函數(shù)。

remove_new:指向新版的移除函數(shù)的指針。新版移除函數(shù)支持更多功能,并可以替代舊版的remove函數(shù)。

通過調(diào)用spi_register_driver函數(shù)并傳入正確配置的struct spi_driver結(jié)構(gòu)體,可以將SPI總線驅(qū)動程序注冊到Linux內(nèi)核,使其能夠接收和處理SPI設(shè)備的相關(guān)操作。

(5)spi_driver類型結(jié)構(gòu)體定義

static struct spi_driver icm20607_driver = {

.driver = {

.name = "icm20607",

.owner = THIS_MODULE,

.of_match_table = icm20607_of__match,

},

.probe = icm20607_probe,

.remove = icm20607_remove,

};

(6)icm20607_of__match實現(xiàn),用來與設(shè)備樹中的compatible匹配

static const struct of_device_id icm20608_of_match[] = {

{ .compatible = "icm20607" },

{ /* Sentinel */ }

};

(7)remove函數(shù)實現(xiàn),執(zhí)行icm20607設(shè)備的清理操作

static int icm20607_remove(struct spi_device *spi)

{

struct icm20607_dev *icm20607dev = spi_get_drvdata(spi);

// 在此處執(zhí)行 ICM20607 設(shè)備的清理操作

//刪除cdev

cdev_del(&icm20607dev->cdev);

//注銷設(shè)備號

unregister_chrdev_region(icm20607dev->dev_num, 1);

//注銷設(shè)備

device_destroy(icm20607dev->class, icm20608dev->dev_num);

//注銷類

class_destroy(icm20607dev->class);

//刪除regmap

regmap_exit(icm20607dev->spi_regmap);

pr_info("ICM20607 SPI device removed successfullyn");

return 0;

}

(8)probe函數(shù)實現(xiàn),此處簡略描述regmap注冊的過程:

static int icm20607_probe(struct spi_device *spi)

{

int ret;

unsigned int whoami;

struct icm20607_dev *icm20607dev;

//分配icm20607dev對象的空間

icm20607dev = devm_kzalloc(&spi->dev, sizeof(*icm20607dev), GFP_KERNEL);

if(!icm20607dev)

return -ENOMEM;

// 創(chuàng)建 ICM20607 設(shè)備的 regmap

icm20608dev->spi_regmap = regmap_init_spi(spi, &spi_regmap_config);

if (IS_ERR(icm20607dev->spi_regmap)) {

dev_err(&spi->dev, "Failed to initialize regmap: %ldn", PTR_ERR(icm20607dev->spi_regmap));

return PTR_ERR(icm20607dev->spi_regmap);

}

......

/*初始化spi_device */

icm20607dev->spi_dev = spi;

spi->mode = SPI_MODE_0;

spi_setup(spi);

/* 初始化ICM20607內(nèi)部寄存器 */

icm20607_reginit(icm20607dev);

/* 保存icm20607dev結(jié)構(gòu)體 */

spi_set_drvdata(spi, icm20607dev);

pr_info("ICM20607 SPI device probed successfullyn");

return 0;

}

probe函數(shù)中首先使用devm_kzalloc函數(shù)分配了icm20607dev的結(jié)構(gòu)體空間,然后使用regmap_init_spi函數(shù)創(chuàng)建regmap實例,再進行spi控制器的初始化和配置,最后對ICM20607的內(nèi)部寄存器進行配置。

其中regmap_init_spi函數(shù)中傳入了“&spi_regmap_config”參數(shù),前邊有提到這個是用來配置regmap對象的,下邊我們看這個參數(shù)是如何定義的。

(9)spi_regmap_config的定義

static const struct regmap_config spi_regmap_config = {

.reg_bits = 8,

.val_bits = 8,

.read_flag_mask = 0x80,

.reg_read = icm20607_spi_read,

.reg_write = icm20607_spi_write,

.max_register = ICM20607_REG_WHOAMI,

};

可以看到這其中規(guī)定了寄存器地址的位數(shù),存儲寄存器的位數(shù),讀寄存器掩碼,讀寄存器函數(shù),寫寄存器函數(shù),最大寄存器地址。

(10)讀寫寄存器函數(shù)實現(xiàn)

static int icm20607_spi_read(struct icm20608_dev *dev, unsigned int reg, unsigned int *val)

{

return regmap_read(dev->spi_regmap, reg, val);

}

static int icm20607_spi_write(struct icm20608_dev *dev, unsigned int reg, unsigned int val)

{

return regmap_write(dev->spi_regmap, reg, val);

}

可以看出讀寫函數(shù)非常簡單明了,直接使用regmap_read和regmap_write函數(shù)即可。

①regmap_read函數(shù)原型如下:

int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val);

該函數(shù)用于從給定的寄存器地址(reg)讀取數(shù)據(jù),并將讀取的值存儲在val指向的變量中。map參數(shù)是一個指向struct regmap的指針,表示寄存器映射對象。返回值為0表示讀取成功,否則表示讀取失敗。

②regmap_write函數(shù)原型如下:

int regmap_write(struct regmap *map, unsigned int reg, unsigned int val);

該函數(shù)用于向給定的寄存器地址(reg)寫入數(shù)據(jù)(val)。map參數(shù)是一個指向struct regmap的指針,表示寄存器映射對象。返回值為0表示寫入成功,否則表示寫入失敗。

三、完整驅(qū)動icm20607.c示例源碼

#include <linux/module.h>

#include <linux/init.h>

#include <linux/fs.h> ??????????// 包含文件系統(tǒng)相關(guān)函數(shù)的頭文件

#include <linux/uaccess.h> ?????// 包含用戶空間數(shù)據(jù)訪問函數(shù)的頭文件

#include <linux/cdev.h> ????????//包含字符設(shè)備頭文件

#include <linux/device.h>

#include <linux/delay.h>

#include <linux/spi/spi.h>

#include <linux/regmap.h>

#include <linux/of.h>

#include <linux/of_address.h>

#include <linux/of_gpio.h>

#include "icm20607.h"

#define ICM20607_REG_WHOAMI ?????0x75

#define ICM20607_WHOAMI_VALUE ???0xAF

#define DEVICE_NAME "icm20607" ?// 設(shè)備名稱

static dev_t dev_num; ??//分配的設(shè)備號

int major; ?//主設(shè)備號

int minor; ?//次設(shè)備號

struct icm20607_dev {

struct spi_device *spi_dev; ????/* spi設(shè)備 */

dev_t dev_num; ?????????????????/* 設(shè)備號*/

struct cdev cdev; ??????????????/* cdev */

struct class *class; ???????????/* 類*/

struct device *device; ?????????/* 設(shè)備 */

struct device_node ?????*nd; ???/* 設(shè)備節(jié)點 */

int cs_gpio; ???????????????????????????/* 片選所使用的GPIO編號 */

signed int gyro_x_adc; ?????????/* 陀螺儀X軸原始值*/

signed int gyro_y_adc; ?????????/* 陀螺儀Y軸原始值*/

signed int gyro_z_adc; ?????????/* 陀螺儀Z軸原始值*/

signed int accel_x_adc; ????????/* 加速度計X軸原始值*/

signed int accel_y_adc; ????????/* 加速度計Y軸原始值*/

signed int accel_z_adc; ????????/* 加速度計Z軸原始值*/

signed int temp_adc; ???????????/* 溫度原始值*/

struct regmap *spi_regmap; ?????????????/* regmap */

struct regmap_config regmap_config;

};

void icm20607_readdata(struct icm20607_dev *dev)

{

u8 ret;

unsigned char data[14];

ret = regmap_bulk_read(dev->spi_regmap, ICM20_ACCEL_XOUT_H, data, 14);/*讀多個寄存器的值*/

dev->accel_x_adc = (signed short)((data[0] << 8) | data[1]);

dev->accel_y_adc = (signed short)((data[2] << 8) | data[3]);

dev->accel_z_adc = (signed short)((data[4] << 8) | data[5]);

dev->temp_adc ???= (signed short)((data[6] << 8) | data[7]);

dev->gyro_x_adc ?= (signed short)((data[8] << 8) | data[9]);

dev->gyro_y_adc ?= (signed short)((data[10] << 8) | data[11]);

dev->gyro_z_adc ?= (signed short)((data[12] << 8) | data[13]);

}

static int icm20607_spi_read(struct icm20607_dev *dev, unsigned int reg, unsigned int *val)

{

return regmap_read(dev->spi_regmap, reg, val);

}

static int icm20607_spi_write(struct icm20607_dev *dev, unsigned int reg, unsigned int val)

{

return regmap_write(dev->spi_regmap, reg, val);

}

static const struct regmap_config spi_regmap_config = {

.reg_bits = 8,

.val_bits = 8,

.read_flag_mask = 0x80,

.reg_read = icm20607_spi_read,

.reg_write = icm20607_spi_write,

.max_register = ICM20607_REG_WHOAMI,

};

static int device_open(struct inode *inode, struct file *file)

{

// 在這里處理設(shè)備打開的操作

printk(KERN_INFO "This is device_open.n");

return 0;

}

static int device_release(struct inode *inode, struct file *file)

{

// 在這里處理設(shè)備關(guān)閉的操作

printk(KERN_INFO "This is device_release.n");

return 0;

}

static ssize_t device_read(struct file *file, char __user *buffer, size_t length, loff_t *offset)

{

signed int data[7];

long err = 0;

struct cdev *cdev = file->f_path.dentry->d_inode->i_cdev;

struct icm20607_dev *dev = container_of(cdev, struct icm20607_dev, cdev);

icm20607_readdata(dev);

data[0] = dev->gyro_x_adc;

data[1] = dev->gyro_y_adc;

data[2] = dev->gyro_z_adc;

data[3] = dev->accel_x_adc;

data[4] = dev->accel_y_adc;

data[5] = dev->accel_z_adc;

data[6] = dev->temp_adc;

err = copy_to_user(buffer, data, sizeof(data));

return 0;

}

static ssize_t device_write(struct file *file, const char __user *buffer, size_t length, loff_t *offset)

{

// 在這里處理設(shè)備寫入的操作

printk(KERN_INFO "This is device_write.n");

return 0;

}

void icm20607_reginit(struct icm20607_dev *dev)

{

u8 value = 0;

icm20607_spi_write(dev, ICM20_PWR_MGMT_1, 0x80);

mdelay(50);

icm20607_spi_write(dev, ICM20_PWR_MGMT_1, 0x01);

mdelay(50);

icm20607_spi_read(dev, ICM20_WHO_AM_I,&value);

printk("ICM20607 ID = %#Xrn", value);

icm20607_spi_write(dev, ICM20_SMPLRT_DIV, 0x00); ?????/* 輸出速率是內(nèi)部采樣率*/

icm20607_spi_write(dev, ICM20_GYRO_CONFIG, 0x18); ?????/* 陀螺儀±2000dps量程 */

icm20607_spi_write(dev, ICM20_ACCEL_CONFIG, 0x18); ????/* 加速度計±16G量程*/

icm20607_spi_write(dev, ICM20_CONFIG, 0x04); ???????????/* 陀螺儀低通濾波BW=20Hz */

icm20607_spi_write(dev, ICM20_ACCEL_CONFIG2, 0x04); /* 加速度計低通濾波BW=21.2Hz */

icm20607_spi_write(dev, ICM20_PWR_MGMT_2, 0x00); ???????/* 打開加速度計和陀螺儀所有軸*/

icm20607_spi_write(dev, ICM20_LP_MODE_CFG, 0x00); ??????/* 關(guān)閉低功耗*/

icm20607_spi_write(dev, ICM20_FIFO_EN, 0x00); ??????????/* 關(guān)閉FIFO */

}

static struct file_operations fops = {

.owner = THIS_MODULE,

.open = device_open,

.release = device_release,

.read = device_read,

.write = device_write,

};

static int icm20607_probe(struct spi_device *spi)

{

int ret;

unsigned int whoami;

struct icm20607_dev *icm20607dev;

/* 分配icm20607dev對象的空間 */

icm20607dev = devm_kzalloc(&spi->dev, sizeof(*icm20607dev), GFP_KERNEL);

if(!icm20607dev)

return -ENOMEM;

// 創(chuàng)建 ICM20607 設(shè)備的 regmap

icm20607dev->spi_regmap = regmap_init_spi(spi, &spi_regmap_config);

if (IS_ERR(icm20607dev->spi_regmap)) {

dev_err(&spi->dev, "Failed to initialize regmap: %ldn", PTR_ERR(icm20607dev->spi_regmap));

return PTR_ERR(icm20607dev->spi_regmap);

}

// 注冊字符設(shè)備驅(qū)動程序

ret = alloc_chrdev_region(&icm20607dev->dev_num,0,1,DEVICE_NAME);

if (ret < 0) {

printk(KERN_ALERT "Failed to allocate device number: %dn", ret);

return ret;

}

major=MAJOR(icm20607dev->dev_num);

minor=MINOR(icm20607dev->dev_num);

printk(KERN_INFO "major number: %dn",major);

printk(KERN_INFO "minor number: %dn",minor);

icm20607dev->cdev.owner = THIS_MODULE;

cdev_init(&icm20607dev->cdev,&fops);

cdev_add(&icm20607dev->cdev,icm20607dev->dev_num,1);

// 創(chuàng)建設(shè)備類

icm20607dev->class = class_create(THIS_MODULE, DEVICE_NAME);

if (IS_ERR(icm20607dev->class)) {

pr_err("Failed to create classn");

return PTR_ERR(icm20607dev->class);

}

// 創(chuàng)建設(shè)備節(jié)點并關(guān)聯(lián)到設(shè)備類

icm20607dev->device = device_create(icm20607dev->class, NULL, MKDEV(major, minor), NULL, DEVICE_NAME);

if (IS_ERR(icm20607dev->device)) {

pr_err("Failed to create devicen");

class_destroy(icm20607dev->class);

return PTR_ERR(icm20607dev->device);

}

/*初始化spi_device */

icm20607dev->spi_dev = spi;

spi->mode = SPI_MODE_0;

spi_setup(spi);

/* 初始化ICM20607內(nèi)部寄存器 */

icm20607_reginit(icm20607dev);

/* 保存icm20607dev結(jié)構(gòu)體 */

spi_set_drvdata(spi, icm20607dev);

pr_info("ICM20607 SPI device probed successfullyn");

return 0;

}

static int icm20607_remove(struct spi_device *spi)

{

struct icm20607_dev *icm20607dev = spi_get_drvdata(spi);

// 在此處執(zhí)行 ICM20607 設(shè)備的清理操作

//刪除cdev

cdev_del(&icm20607dev->cdev);

//注銷設(shè)備號

unregister_chrdev_region(icm20607dev->dev_num, 1);

//注銷設(shè)備

device_destroy(icm20607dev->class, icm20607dev->dev_num);

//注銷類

class_destroy(icm20607dev->class);

//刪除regmap

regmap_exit(icm20607dev->spi_regmap);

pr_info("ICM20607 SPI device removed successfullyn");

return 0;

}

static const struct of_device_id icm20607_of__match[] = {

{ .compatible = "icm20607", },

{},

};

static struct spi_driver icm20607_driver = {

.driver = {

.name = "icm20607",

.owner = THIS_MODULE,

.of_match_table = icm20607_of__match,

},

.probe = icm20607_probe,

.remove = icm20607_remove,

};

static int __init icm20607_init(void)

{

int ret;

ret = spi_register_driver(&icm20607_driver);

if (ret < 0) {

pr_err("Failed to register ICM20607 driver: %dn", ret);

return ret;

}

pr_info("ICM20607 SPI device driver loadedn");

return 0;

}

static void __exit icm20607_exit(void)

{

spi_unregister_driver(&icm20607_driver);

pr_info("ICM20607 SPI device driver unloadedn");

}

module_init(icm20607_init);

module_exit(icm20607_exit);

MODULE_LICENSE("GPL");

MODULE_AUTHOR("Your Name");

MODULE_DESCRIPTION("ICM20607 SPI device driver");

四、編譯

Makefile修改如下:

. /opt/fsl-imx-x11/4.1.15-2.0.0/environment-setup-cortexa7hf-neon-poky-linux-gnueabi

elf@ubuntu:~/work/test/09_Regmap子系統(tǒng)-icm20607/icm20607$ make

將編譯生成的icm20607.ko模塊拷貝到開發(fā)板。

五、編寫測試源碼icm20607_app.c

測試源碼中循環(huán)讀取驅(qū)動傳到用戶空間的數(shù)據(jù):

#include "stdio.h"

#include "unistd.h"

#include "sys/types.h"

#include "sys/stat.h"

#include "sys/ioctl.h"

#include "fcntl.h"

#include "stdlib.h"

#include "string.h"

#include <poll.h>

#include <sys/select.h>

#include <sys/time.h>

#include <signal.h>

#include <fcntl.h>

#define ICM20607_DEV "/dev/icm20607"

int main(int argc, char *argv[])

{

int fd;

signed int databuf[7];

unsigned char data[14];

signed int gyro_x_adc, gyro_y_adc, gyro_z_adc;

signed int accel_x_adc, accel_y_adc, accel_z_adc;

signed int temp_adc;

float gyro_x_act, gyro_y_act, gyro_z_act;

float accel_x_act, accel_y_act, accel_z_act;

float temp_act;

int ret = 0;

fd = open(ICM20607_DEV, O_RDWR);

if(fd < 0) {

printf("can't open file %srn", ICM20607_DEV);

return -1;

}

while (1) {

ret = read(fd, databuf, sizeof(databuf));

if(ret == 0) { /*讀取出原始值 */

gyro_x_adc = databuf[0];

gyro_y_adc = databuf[1];

gyro_z_adc = databuf[2];

accel_x_adc = databuf[3];

accel_y_adc = databuf[4];

accel_z_adc = databuf[5];

temp_adc = databuf[6];

/* 轉(zhuǎn)換為實際值 */

gyro_x_act = (float)(gyro_x_adc) ?/ 16.4;

gyro_y_act = (float)(gyro_y_adc) ?/ 16.4;

gyro_z_act = (float)(gyro_z_adc) ?/ 16.4;

accel_x_act = (float)(accel_x_adc) / 2048;

accel_y_act = (float)(accel_y_adc) / 2048;

accel_z_act = (float)(accel_z_adc) / 2048;

temp_act = ((float)(temp_adc) - 25 ) / 326.8 + 25;

printf("rn");

printf("raw value:rn");

printf("gx = %d, gy = %d, gz = %drn", gyro_x_adc, gyro_y_adc, gyro_z_adc);

printf("ax = %d, ay = %d, az = %drn", accel_x_adc, accel_y_adc, accel_z_adc);

printf("temp = %drn", temp_adc);

printf("rn");

printf("act value:rn");

printf("act gx = %.2f度/S, act gy = %.2f度/S, act gz = %.2f度/Srn", gyro_x_act, gyro_y_act, gyro_z_act);

printf("act ax = %.2fg, act ay = %.2fg, act az = %.2fgrn", accel_x_act, accel_y_act, accel_z_act);

printf("act temp = %.2f攝氏度rn", temp_act);

}

usleep(100000); /*100ms */

}

close(fd);

return 0;

}

六、編譯應(yīng)用

. /opt/fsl-imx-x11/4.1.15-2.0.0/environment-setup-cortexa7hf-neon-poky-linux-gnueabi

elf@ubuntu:~/work/test/09_Regmap子系統(tǒng)-icm20607/icm20607_app$ $CC icm20607_app.c -o icm20607_app

將編譯好的測試應(yīng)用拷貝到開發(fā)板。

七、測試

root@ELF1:~#:~#?insmod elf-icm20607.ko

major number: 249

minor number: 0

ICM20607 ID = 0X0

ICM20607 SPI device probed successfully

ICM20607 SPI device driver loaded

root@ELF1:~#:~# ./icm20607_app

This is device_open.

raw value:

gx = 0, gy = 0, gz = 0

ax = 0, ay = 0, az = 0

temp = 0

act value:

act gx = 0.00度/S, act gy = 0.00度/S, act gz = 0.00度/S

act ax = 0.00g, act ay = 0.00g, act az = 0.00g

act temp = 24.92攝氏度

可以看到測試app將六軸傳感器的原始值和轉(zhuǎn)換后的值打印了出來。

相關(guān)推薦