中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁(yè) > news >正文

建設(shè)黨史網(wǎng)站的意義在線智能識(shí)圖

建設(shè)黨史網(wǎng)站的意義,在線智能識(shí)圖,織夢(mèng)優(yōu)美文章閱讀網(wǎng)站源碼,網(wǎng)絡(luò)游戲名字目錄 一、Linux I2C 驅(qū)動(dòng)簡(jiǎn)介 1、I2C 總線驅(qū)動(dòng) 2、I2C 設(shè)備驅(qū)動(dòng) 1、 i2c_client 結(jié)構(gòu)體 2、 i2c_driver 結(jié)構(gòu)體 二、硬件分析 三、設(shè)備樹編寫 1、pinctrl_i2c1 2、在 i2c1 節(jié)點(diǎn)追加 ap3216c 子節(jié)點(diǎn) 3、驗(yàn)證 四、 代碼編寫 1、makefile 2、ap3216c.h 3、ap3216c.c …

目錄

一、Linux I2C 驅(qū)動(dòng)簡(jiǎn)介

1、I2C 總線驅(qū)動(dòng)

2、I2C 設(shè)備驅(qū)動(dòng)

1、 i2c_client 結(jié)構(gòu)體

2、 i2c_driver 結(jié)構(gòu)體

二、硬件分析

三、設(shè)備樹編寫

1、pinctrl_i2c1

2、在 i2c1 節(jié)點(diǎn)追加 ap3216c 子節(jié)點(diǎn)

3、驗(yàn)證

四、?代碼編寫

1、makefile

2、ap3216c.h

?3、ap3216c.c

①、頭文件

②、驅(qū)動(dòng)出入口?

③、 i2c驅(qū)動(dòng)結(jié)構(gòu)體?

④、匹配函數(shù)

⑤、probe 函數(shù)

⑥、remove?函數(shù)

?⑦、函數(shù)入口出口添加注冊(cè)i2c_drive

⑧、讀取AP3216C的N個(gè)寄存器

⑨、向AP3216C的N個(gè)寄存器寫數(shù)據(jù)

⑩、讀、寫AP3216C一個(gè)寄存器

⑩①、讀取AP3216C的數(shù)據(jù)

⑩②完善ap3216c_open、read函數(shù)

?代碼如下

?

4、ap3216c.c


一、Linux I2C 驅(qū)動(dòng)簡(jiǎn)介

? ? ? ? 在IMX6ULL開發(fā)篇中"IIC實(shí)驗(yàn)"寫了四個(gè)文件: bsp_i2c.c、bsp_i2c.h、 bsp_ap3216c.c 和 bsp_ap3216c.h。其中前兩個(gè)是 I.MX6U 的 IIC 接口驅(qū)動(dòng),后兩個(gè)文件是 AP3216C 這個(gè) I2C 設(shè)備驅(qū)動(dòng)文件。相當(dāng)于有兩部分驅(qū)動(dòng):
①、 I2C 主機(jī)驅(qū)動(dòng)。
②、 I2C 設(shè)備驅(qū)動(dòng)。
????????對(duì)于 I2C 主機(jī)驅(qū)動(dòng),一旦編寫完成就不需要再做修改,其他的 I2C 設(shè)備直接調(diào)用主機(jī)驅(qū)動(dòng)提供的 API 函數(shù)完成讀寫操作即可。這個(gè)正好符合 Linux 的驅(qū)動(dòng)分離與分層的思想,因此 Linux內(nèi)核也將 I2C 驅(qū)動(dòng)分為兩部分:
①、 I2C 總線驅(qū)動(dòng), I2C 總線驅(qū)動(dòng)就是 SOC 的 I2C 控制器驅(qū)動(dòng),也叫做 I2C 適配器驅(qū)動(dòng)。
②、 I2C 設(shè)備驅(qū)動(dòng), I2C 設(shè)備驅(qū)動(dòng)就是針對(duì)具體的 I2C 設(shè)備而編寫的驅(qū)動(dòng)

1、I2C 總線驅(qū)動(dòng)

????????在”platform驅(qū)動(dòng)實(shí)驗(yàn)"的時(shí)候就說(shuō)過(guò), platform 是虛擬出來(lái)的一條總線,目的是為了實(shí)現(xiàn)總線、設(shè)備、驅(qū)動(dòng)框架。對(duì)于 I2C 而言,不需要虛擬出一條總線,直接使用 I2C總線即可。 I2C 總線驅(qū)動(dòng)重點(diǎn)是 I2C 適配器(也就是 SOC 的 I2C 接口控制器)驅(qū)動(dòng),Linux 內(nèi)核將 SOC 的 I2C 適配器(控制器)抽象成 i2c_adapter, i2c_adapter 結(jié)構(gòu)體定義在 include/linux/i2c.h 文件中,i2c_algorithm 類型的指針變量 algo,對(duì)于一個(gè) I2C 適配器,肯定要對(duì)外提供讀寫 API 函數(shù),設(shè)備驅(qū)動(dòng)程序可以使用這些 API 函數(shù)來(lái)完成讀寫操作。 i2c_algorithm 就是 I2C 適配器與 IIC 設(shè)備進(jìn)行通信的方法;i2c_algorithm 結(jié)構(gòu)體定義在 include/linux/i2c.h 文件中,其中的master_xfer 就是 I2C 適配器的傳輸函數(shù),可以通過(guò)此函數(shù)來(lái)完成與 IIC 設(shè)備之間的通信,smbus_xfer 是 SMBUS 總線的傳輸函數(shù)

????????一般 SOC 的 I2C 總線驅(qū)動(dòng)都是由半導(dǎo)體廠商編寫的,比如 I.MX6U 的 I2C 適配器驅(qū)動(dòng) NXP 已經(jīng)編寫好了,這個(gè)不需要用戶去編寫。因此 I2C 總線驅(qū)動(dòng)對(duì)我們這些 SOC 使用者來(lái)說(shuō)是被屏蔽掉的,我們只要專注于 I2C 設(shè)備驅(qū)動(dòng)即可。

2、I2C 設(shè)備驅(qū)動(dòng)

????????I2C 設(shè)備驅(qū)動(dòng)重點(diǎn)關(guān)注兩個(gè)數(shù)據(jù)結(jié)構(gòu): i2c_client 和 i2c_driver,i2c_client 就是描述設(shè)備信息的, i2c_driver 描述驅(qū)動(dòng)內(nèi)容,類似于 platform_driver

1、 i2c_client 結(jié)構(gòu)體

i2c_client 結(jié)構(gòu)體定義在 include/linux/i2c.h 文件中,內(nèi)容如下:

struct i2c_client {unsigned short flags;     /* 標(biāo)志 */unsigned short addr;     /* 芯片地址, 7 位,存在低 7 位*/
......char name[I2C_NAME_SIZE]; /* 名字 */struct i2c_adapter *adapter; /* 對(duì)應(yīng)的 I2C 適配器 */struct device dev;     /* 設(shè)備結(jié)構(gòu)體 */int irq;             /* 中斷 */struct list_head detected;
......};

一個(gè)設(shè)備對(duì)應(yīng)一個(gè) i2c_client,每檢測(cè)到一個(gè) I2C 設(shè)備就會(huì)給這個(gè) I2C 設(shè)備分配一個(gè)i2c_client

2、 i2c_driver 結(jié)構(gòu)體

i2c_driver 類似 platform_driver,i2c_driver 結(jié)構(gòu)體定義在 include/linux/i2c.h 文件中,部分如下

 struct i2c_driver {........./* Standard driver model interfaces */
1    int (*probe)(struct i2c_client *, const struct i2c_device_id *);......
2    struct device_driver driver;
3    const struct i2c_device_id *id_table;..........}

第 1?行,當(dāng) I2C 設(shè)備和驅(qū)動(dòng)匹配成功以后 probe 函數(shù)就會(huì)執(zhí)行,和 platform 驅(qū)動(dòng)一樣。
第 2行, device_driver 驅(qū)動(dòng)結(jié)構(gòu)體,如果使用設(shè)備樹的話,需要設(shè)置 device_driver

????????????????of_match_table 成員變量,也就是驅(qū)動(dòng)的兼容(compatible)屬性。
第3行, id_table 是傳統(tǒng)的、未使用設(shè)備樹的設(shè)備匹配 ID 表

重點(diǎn)工作就是構(gòu)建 i2c_driver,構(gòu)建完成以后需要向Linux 內(nèi)核注冊(cè)這個(gè) i2c_driver

二、硬件分析

這部分在在IMX6ULL開發(fā)篇中"IIC實(shí)驗(yàn)"有詳細(xì)介紹,下面就簡(jiǎn)單介紹

打開AP3216C原理圖,這是一個(gè)IIC接口的器件,是一個(gè)環(huán)境光傳感器

?I2C1_SCL: 使用的是UART4_TXD這個(gè)IO;I2C1_SDA: 使用的是UART4_RXD這個(gè)IO

打開ap3216數(shù)據(jù)手冊(cè)

地址為0x1e

三、設(shè)備樹編寫

1、pinctrl_i2c1

打開設(shè)備樹,找到i2c1,pinctrl_i2c1 就是 I2C1 的 IO 節(jié)點(diǎn)

????????這里將 UART4_TXD 和 UART4_RXD 這兩個(gè) IO 分別復(fù)用為 I2C1_SCL 和 I2C1_SDA,電氣屬性都設(shè)置為 0x4001b8b0

2、在 i2c1 節(jié)點(diǎn)追加 ap3216c 子節(jié)點(diǎn)

????????AP3216C 是連接到 I2C1 上的,因此需要在 i2c1 節(jié)點(diǎn)下添加 ap3216c 的設(shè)備子節(jié)點(diǎn),默認(rèn)內(nèi)容如下

305-316行,NXP 官方的 EVK 開發(fā)板上接了 mag3110和fxls8471,這里使用的開發(fā)板并沒(méi)有這這兩個(gè)器件,所以刪掉,并添加上我們使用的

300行,clock-frequency 屬性為 I2C 頻率,這里設(shè)置為 100KHz

302行,inctrl-0 屬性指定 I2C 所使用的 IO 為上面的pinctrl_i2c1

305行,ap3216c 子節(jié)點(diǎn), @后面的“1e”是 ap3216c 的器件地址

306行,設(shè)置 compatible 值為“my,ap3216c”

307行,reg 屬性也是設(shè)置 ap3216c 器件地址的,因此 reg 設(shè)置為 0x1e

3、驗(yàn)證

改完成以后使用“make dtbs”重新編譯一下,然后使用新的設(shè)備樹啟動(dòng) Linux 內(nèi)核

/sys/bus/i2c/devices 目錄下存放著所有 I2C 設(shè)備,如果設(shè)備樹修改正確的話,會(huì)在/sys/bus/i2c/devices 目錄下看到一個(gè)名為“0-001e”的子目錄,如下

“0-001e”就是 ap3216c 的設(shè)備目錄,“1e”就是 ap3216c 器件地址。進(jìn)入0-001e 目錄,可以看到“name”文件, name 問(wèn)價(jià)就保存著此設(shè)備名字,在這里就是“ap3216c”,如下

四、?代碼編寫

1、makefile

需要的文件如下圖左,修改makefile

2、ap3216c.h

定義器件及其寄存器地址

?3、ap3216c.c

①、頭文件

②、驅(qū)動(dòng)出入口?

?

③、 i2c驅(qū)動(dòng)結(jié)構(gòu)體?

46行,當(dāng) I2C 設(shè)備和驅(qū)動(dòng)匹配成功以后 probe 函數(shù)就會(huì)執(zhí)行,和 platform 驅(qū)動(dòng)一樣

47行,當(dāng)關(guān)閉 驅(qū)動(dòng)的時(shí)候remove?函數(shù)就會(huì)執(zhí)行,和 platform 驅(qū)動(dòng)一樣

49行,name是在無(wú)設(shè)備樹時(shí)用于和設(shè)備進(jìn)行匹配,也就是上面寫的實(shí)驗(yàn),也作為驅(qū)動(dòng)名字;

? ? ? ? 使用設(shè)備樹就設(shè)置of_match_table變量,也就是驅(qū)動(dòng)的兼容(compatible)屬性
53行,id_table 是傳統(tǒng)的、未使用設(shè)備樹的設(shè)備匹配 ID 表

④、匹配函數(shù)

i2c驅(qū)動(dòng)結(jié)構(gòu)體 里對(duì)應(yīng)的函數(shù)

?236行,無(wú)設(shè)備樹的時(shí)候匹配 ID 表
241行,設(shè)備樹所使用的匹配表

⑤、probe 函數(shù)

在這里面實(shí)現(xiàn)基本的字符設(shè)備

#define AP3216C_CNT 1
#define AP3216C_NAME "ap3216c"struct ap3216c_dev{int devid;int major;int minor;struct cdev cedv;struct class *class;struct device *device;void *private_data;/*私有數(shù)據(jù)*/unsigned short ir, als, ps;		/* 三個(gè)光傳感器數(shù)據(jù) */ 
};
static struct ap3216c_dev ap3216cdev;
static int ap3216c_open(struct inode *inode, struct file *filp)
{return 0;
}static int ap3216c_release(struct inode *inode, struct file *filp)
{printk("ap3216c_release\r\n");return 0;
}
static ssize_t ap3216c_read(struct file *filp, char __user *buf, size_t cnt, loff_t *off)
{return 0;
}static struct file_operations ap3216c_fops  = {.owner  =   THIS_MODULE,.open   =   ap3216c_open,.read   =   ap3216c_read,.release = ap3216c_release,
};static int ap3216c_probe(struct i2c_client *client,const struct i2c_device_id *id)
{int ret =0;/*搭建字符設(shè)備驅(qū)動(dòng)框架*//*1、創(chuàng)建字符設(shè)備*/ap3216cdev.major=0;if(ap3216cdev.major){ap3216cdev.devid = MKDEV(ap3216cdev.major,0);ret = register_chrdev_region(ap3216cdev.devid,AP3216C_CNT,AP3216C_NAME);}else{ret = alloc_chrdev_region(&ap3216cdev.devid,0,AP3216C_CNT,AP3216C_NAME);ap3216cdev.major = MAJOR(ap3216cdev.devid);ap3216cdev.minor = MINOR(ap3216cdev.devid);}if(ret < 0){printk("ap3216cdev_chrdev_region error!\r\n");goto fail_devid;}printk("ap3216cde major: %d minor: %d\r\n",ap3216cdev.major,ap3216cdev.minor);/*2、注冊(cè)字符設(shè)備*/ap3216cdev.cedv.owner = THIS_MODULE;cdev_init(&ap3216cdev.cedv,&ap3216c_fops);ret = cdev_add(&ap3216cdev.cedv,ap3216cdev.devid,AP3216C_CNT);if(ret < 0){printk("cdev_add error!\r\n");goto fail_cdev;}/*3、自動(dòng)創(chuàng)建設(shè)備節(jié)點(diǎn)*/ap3216cdev.class = class_create(THIS_MODULE,AP3216C_NAME);if(IS_ERR(ap3216cdev.class)){ret = PTR_ERR(ap3216cdev.class);goto fail_class;}ap3216cdev.device = device_create(ap3216cdev.class, NULL,ap3216cdev.devid, NULL,AP3216C_NAME);if(IS_ERR(ap3216cdev.device)){ret = PTR_ERR(ap3216cdev.device);goto fail_device;}printk("ap3216c_probe\r\n");ap3216cdev.private_data = client;return 0;
fail_device:class_destroy(ap3216cdev.class);
fail_class:cdev_del(&ap3216cdev.cedv);
fail_cdev:unregister_chrdev_region(ap3216cdev.devid,AP3216C_CNT);
fail_devid:return ret;
}

" return 0 "前一行,將此函數(shù)的第一 個(gè)參數(shù) client 傳遞給 ap3216cdev 的 private_data 成員變量

當(dāng)設(shè)備和驅(qū)動(dòng)匹配成功后,probe函數(shù)執(zhí)行,傳遞的第一個(gè)參數(shù)就是i2c_client ,i2c_client 每檢測(cè)到一個(gè) I2C 設(shè)備就會(huì)給這個(gè) I2C 設(shè)備分配一個(gè)i2c_client,這里用 ap3216cdev結(jié)構(gòu)體中的private_data 成員接收

⑥、remove?函數(shù)

?⑦、函數(shù)入口出口添加注冊(cè)i2c_drive

?

50行,調(diào)用 i2c_add_driver 來(lái)向 Linux 內(nèi) 核注冊(cè) i2c_driver,也就是 ap3216c_driver

i2c_add_driver 是一個(gè)宏,定義如下:

#define i2c_add_driver(driver) \
?????????i2c_register_driver(THIS_MODULE, driver)

i2c_add_driver 就是對(duì) i2c_register_driver 做了一個(gè)簡(jiǎn)單的封裝,只有一個(gè)參數(shù),就是要注冊(cè)的 i2c_driver。

66行,調(diào)用 i2c_del_driver 來(lái)注銷掉前面 注冊(cè)的 ap3216c_driver,函數(shù)原型如下:

void i2c_del_driver(struct i2c_driver *driver)

driver:要注銷的 i2c_driver。返回值: 無(wú)。

⑧、讀取AP3216C的N個(gè)寄存器

?這里先看61行,一般需要在 probe 函數(shù)里面初始化 I2C 設(shè)備,要初始化 I2C 設(shè)備就必須能夠?qū)?I2C 設(shè)備寄存器進(jìn)行讀寫操作,這里就要用到 i2c_transfer 函數(shù)了,i2c_transfer 函數(shù)最終會(huì)調(diào)用 I2C 適配器中 i2c_algorithm 里面的 master_xfer 函數(shù),對(duì)于 I.MX6U 而言就是i2c_imx_xfer 這個(gè)函數(shù)。 i2c_transfer 函數(shù)原型如下:

int i2c_transfer(struct i2c_adapter *adap,

????????????????????????????????struct i2c_msg *msgs,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int num)

adap: 所使用的 I2C 適配器, i2c_client 會(huì)保存其對(duì)應(yīng)的 i2c_adapter。
msgs: I2C 要發(fā)送的一個(gè)或多個(gè)消息。
num: 消息數(shù)量,也就是 msgs 的數(shù)量。
返回值: 負(fù)值,失敗,其他非負(fù)值,發(fā)送的 msgs 數(shù)量

?從上面介紹i2c_client結(jié)構(gòu)體就能看到有adapter成員,在probe函數(shù)里面已經(jīng)獲取到ap3216cdev設(shè)備的private_data成員中

48行,就是把private_data成員中把私有數(shù)據(jù)提出來(lái),就在61行第一個(gè)參數(shù)中使用i2c_client中的adapter成員

繼續(xù)看 i2c_transfer 函數(shù)msgs 這個(gè)參數(shù),這是一個(gè) i2c_msg 類型的指針參數(shù), I2C 進(jìn)行數(shù)據(jù)收發(fā)
說(shuō)白了就是消息的傳遞, Linux 內(nèi)核使用 i2c_msg 結(jié)構(gòu)體來(lái)描述一個(gè)消息。 i2c_msg 結(jié)構(gòu)體定義
在 include/uapi/linux/i2c.h 文件中

?69行,從機(jī)地址

?70行,標(biāo)志

72行,read data,讀數(shù)據(jù)

79行,要發(fā)送消息(本 msg)長(zhǎng)度

80行,發(fā)送消息的數(shù)據(jù)

47行,定義結(jié)構(gòu)體數(shù)組,按照I2C讀時(shí)序把操作分為兩部分

前面兩段作為一部分,就是50-54行;后面兩段作另一部分,就是56-59行

50-54行,發(fā)送器件寄存器地址。從i2c_client中獲取從機(jī)地址,標(biāo)志為0,表示發(fā)送數(shù)據(jù),要發(fā)送的數(shù)據(jù),也就是器件寄存器地址,寄存器地址長(zhǎng)度為1個(gè)字節(jié)

56-59行,讀取數(shù)據(jù)。從i2c_client中獲取從機(jī)地址,標(biāo)志表示讀數(shù)據(jù),讀出來(lái)的數(shù)據(jù)保存在val,最后為讀取的長(zhǎng)度

再回到61行,第二個(gè)參數(shù)就是結(jié)構(gòu)體數(shù)組msg,第三個(gè)參數(shù)就是2,結(jié)構(gòu)體數(shù)組msg的長(zhǎng)度

⑨、向AP3216C的N個(gè)寄存器寫數(shù)據(jù)

?76行,這里根據(jù)I2C寫時(shí)序,寄存器地址和數(shù)據(jù)一次可以發(fā)完,所以只需要一個(gè)msg即可

79行,寄存器地址保存在b[0],先發(fā)寄存器地址

80行,把要發(fā)送的數(shù)據(jù)拷貝到b數(shù)組里面

⑩、讀、寫AP3216C一個(gè)寄存器

?就是調(diào)用函數(shù)

⑩①、讀取AP3216C的數(shù)據(jù)

⑩②完善ap3216c_open、read函數(shù)

?

?代碼如下

?

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/slab.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/atomic.h>
#include <linux/timer.h>
#include <linux/jiffies.h>
#include <linux/string.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include "ap3216c.h"#define AP3216C_CNT 1
#define AP3216C_NAME "ap3216c"struct ap3216c_dev{int devid;/* 設(shè)備號(hào) 	 */int major;int minor;struct cdev cedv;/* cdev 	*/struct class *class;/* 類 		*/struct device *device;/* 設(shè)備 	 */void *private_data;/*私有數(shù)據(jù)*/unsigned short ir, als, ps;		/* 三個(gè)光傳感器數(shù)據(jù) */ 
};static struct ap3216c_dev ap3216cdev;/*讀取AP3216C的N個(gè)寄存器*/
static int ap3216c_read_regs(struct ap3216c_dev *dev,u8 reg,void *val, int len)
{int ret;struct i2c_msg msg[2];struct i2c_client *client = (struct i2c_client *)dev->private_data;/*msg[0]發(fā)送要讀取的寄存器首地址*/msg[0].addr = client->addr;/*從機(jī)地址,也就是ap3216c*/msg[0].flags = 0;/* 標(biāo)記為發(fā)送數(shù)據(jù) */msg[0].buf = &reg;/*要發(fā)送的數(shù)據(jù),也就是寄存器地址*/msg[0].len = 1;/*要發(fā)送的寄存器地址長(zhǎng)度為1*//*msg[1]讀取數(shù)據(jù)*/msg[1].addr = client->addr;/*從機(jī)地址,也就是ap3216c*/msg[1].flags = I2C_M_RD;/*表示讀數(shù)據(jù)*/msg[1].buf = val;/*接收到的從機(jī)地址*/msg[1].len = len;/*要讀取的寄存器數(shù)據(jù)長(zhǎng)度*/ret = i2c_transfer(client->adapter,msg,2);if(ret == 2){ret = 0;}else{printk("i2c rd failed=%d reg=%06x len=%d\n",ret, reg, len);ret = -EREMOTEIO;}return ret;
}/*向AP3216C的N個(gè)寄存器寫數(shù)據(jù)*/
static int ap3216c_write_regs(struct ap3216c_dev *dev,u8 reg,u8 *buf , u8 len)
{u8 b[256];struct i2c_msg msg;struct i2c_client *client = (struct i2c_client *)dev->private_data;/*構(gòu)建要發(fā)送的數(shù)據(jù),也就是寄存器首地址+實(shí)際的數(shù)據(jù)*/b[0] = reg;/*msg[0]發(fā)送要讀取的寄存器首地址*/memcpy(&b[1], buf, len);msg.addr = client->addr;/*從機(jī)地址,也就是ap3216c*/msg.flags = 0;/*表示為要發(fā)送的數(shù)據(jù)*/msg.buf = b;/*要發(fā)送的數(shù)據(jù),寄存器首地址+實(shí)際的數(shù)據(jù)*/msg.len = len +1;/*要發(fā)送的數(shù)據(jù)長(zhǎng)度:寄存器首地址+實(shí)際的數(shù)據(jù)*/return i2c_transfer(client->adapter,&msg,1);
}
/*讀取AP3216C一個(gè)寄存器*/
static unsigned char ap3216c_read_reg(struct ap3216c_dev *dev,u8 reg)
{u8 data=0;ap3216c_read_regs(dev,reg,&data,1);return data;
}
/*向AP3216C一個(gè)寄存器寫數(shù)據(jù)*/
static void ap3216c_write_reg(struct ap3216c_dev *dev, u8 reg , u8 data)
{u8 buf = data;ap3216c_write_regs(dev,reg,&buf,1);
}void ap3216c_readdata(struct ap3216c_dev *dev)
{unsigned char i =0;unsigned char buf[6];/* 循環(huán)讀取所有傳感器數(shù)據(jù) */for(i = 0; i < 6; i++)	{buf[i] = ap3216c_read_reg(dev, AP3216C_IRDATALOW + i);	}if(buf[0] & 0X80) 	/* IR_OF位為1,則數(shù)據(jù)無(wú)效 */dev->ir = 0;					else 				/* 讀取IR傳感器的數(shù)據(jù)   		*/dev->ir = ((unsigned short)buf[1] << 2) | (buf[0] & 0X03); 			dev->als = ((unsigned short)buf[3] << 8) | buf[2];	/* 讀取ALS傳感器的數(shù)據(jù) 			 */  if(buf[4] & 0x40)	/* IR_OF位為1,則數(shù)據(jù)無(wú)效 			*/dev->ps = 0;    													else 				/* 讀取PS傳感器的數(shù)據(jù)    */dev->ps = ((unsigned short)(buf[5] & 0X3F) << 4) | (buf[4] & 0X0F); 
}static int ap3216c_open(struct inode *inode, struct file *filp)
{unsigned char value = 0;filp->private_data = &ap3216cdev;printk("ap3216c_open\r\n");/*初始化ap3216c*/ap3216c_write_reg(&ap3216cdev,AP3216C_SYSTEMCONG,0x4);/*復(fù)位*/mdelay(50);/*50ms*/ap3216c_write_reg(&ap3216cdev,AP3216C_SYSTEMCONG,0x3);/*復(fù)位*/value = ap3216c_read_reg(&ap3216cdev,AP3216C_SYSTEMCONG);printk("AP3216C_SYSTEMCONG = %#x\r\n",value);return 0;
}static int ap3216c_release(struct inode *inode, struct file *filp)
{printk("ap3216c_release\r\n");return 0;
}
static ssize_t ap3216c_read(struct file *filp, char __user *buf, size_t cnt, loff_t *off)
{long err=0;short data[3];struct ap3216c_dev *dev = (struct ap3216c_dev *)filp->private_data;/*向應(yīng)用返回AP3216C的原始數(shù)據(jù)*/ap3216c_readdata(dev);data[0] =dev->ir;data[1] =dev->als;data[2] =dev->ps;err = copy_to_user(buf, data,sizeof(data));return 0;
}static struct file_operations ap3216c_fops  = {.owner  =   THIS_MODULE,.open   =   ap3216c_open,.read   =   ap3216c_read,.release = ap3216c_release,
};static int ap3216c_probe(struct i2c_client *client,const struct i2c_device_id *id)
{int ret =0;/*搭建字符設(shè)備驅(qū)動(dòng)框架*//*1、創(chuàng)建字符設(shè)備*/ap3216cdev.major=0;if(ap3216cdev.major){ap3216cdev.devid = MKDEV(ap3216cdev.major,0);ret = register_chrdev_region(ap3216cdev.devid,AP3216C_CNT,AP3216C_NAME);}else{ret = alloc_chrdev_region(&ap3216cdev.devid,0,AP3216C_CNT,AP3216C_NAME);ap3216cdev.major = MAJOR(ap3216cdev.devid);ap3216cdev.minor = MINOR(ap3216cdev.devid);}if(ret < 0){printk("ap3216cdev_chrdev_region error!\r\n");goto fail_devid;}printk("ap3216cde major: %d minor: %d\r\n",ap3216cdev.major,ap3216cdev.minor);/*2、注冊(cè)字符設(shè)備*/ap3216cdev.cedv.owner = THIS_MODULE;cdev_init(&ap3216cdev.cedv,&ap3216c_fops);ret = cdev_add(&ap3216cdev.cedv,ap3216cdev.devid,AP3216C_CNT);if(ret < 0){printk("cdev_add error!\r\n");goto fail_cdev;}/*3、自動(dòng)創(chuàng)建設(shè)備節(jié)點(diǎn)*/ap3216cdev.class = class_create(THIS_MODULE,AP3216C_NAME);if(IS_ERR(ap3216cdev.class)){ret = PTR_ERR(ap3216cdev.class);goto fail_class;}ap3216cdev.device = device_create(ap3216cdev.class, NULL,ap3216cdev.devid, NULL,AP3216C_NAME);if(IS_ERR(ap3216cdev.device)){ret = PTR_ERR(ap3216cdev.device);goto fail_device;}printk("ap3216c_probe\r\n");ap3216cdev.private_data = client;return 0;
fail_device:class_destroy(ap3216cdev.class);
fail_class:cdev_del(&ap3216cdev.cedv);
fail_cdev:unregister_chrdev_region(ap3216cdev.devid,AP3216C_CNT);
fail_devid:return ret;
}
static int ap3216c_remove(struct i2c_client *client)
{cdev_del(&ap3216cdev.cedv);unregister_chrdev_region(ap3216cdev.devid,AP3216C_CNT);device_destroy(ap3216cdev.class, ap3216cdev.devid);class_destroy(ap3216cdev.class);printk("ap3216c_remove\r\n");return 0;
}
/*傳統(tǒng)匹配表*/
static struct i2c_device_id ap3216c_id[] = {{"my,ap3216c",0},{}
};
/*設(shè)備樹匹配*/
static struct of_device_id ap3216c_of_match[] = {{.compatible = "my,ap3216c"},{}
};
/*i2c_driver*/
static struct i2c_driver ap3216c_driver= {.probe = ap3216c_probe,.remove = ap3216c_remove,.driver = {.name = "ap3216c",.owner = THIS_MODULE,.of_match_table = of_match_ptr(ap3216c_of_match),},.id_table = ap3216c_id,
};
/*驅(qū)動(dòng)入口*/
static int __init ap3216c_init(void)
{int ret = 0;/*添加*/ret = i2c_add_driver(&ap3216c_driver);return ret;
}
/*驅(qū)動(dòng)出口*/
static void __exit ap3216c_exit(void)
{i2c_del_driver(&ap3216c_driver);
}module_init(ap3216c_init);
module_exit(ap3216c_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("ba che kai qi lai");

4、ap3216c.c

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <linux/input.h>/*argc:應(yīng)用程序參數(shù)個(gè)數(shù)(argv數(shù)組元素個(gè)數(shù))argv:具體參數(shù),也可以寫作char **argv./ap3216cAPP <filename>    ./ap3216cAPP  /dev/ap3216c
*/int main(int argc, char *argv[])
{int fd,err;char *filename;unsigned short ir, als, ps, data[3];/*判斷命令行輸入?yún)?shù)是否正確*/if(argc != 2){printf("error usage!\r\n");return -1;}/*用指針指向文件*/filename = argv[1];/*打開文件*/fd = open(filename , O_RDWR);if(fd < 0){printf("file open failed\r\n",filename);return -1;}while(1){err =read(fd,&data,sizeof(data));if(err == 0){ir=data[0];als=data[1];ps=data[2] ;printf("ap3216c ir = %d,als = %d,ps = %d\r\n",ir,als,ps);}usleep(200000);/*200ms*/}/*關(guān)閉文件*/close(fd);return 0;
}

?用APP測(cè)試驅(qū)動(dòng)

?用手接近和用燈照ap3216c傳感器,數(shù)值都會(huì)發(fā)生變化

http://www.risenshineclean.com/news/64016.html

相關(guān)文章:

  • 比價(jià)網(wǎng)站源碼整站程序百度上做優(yōu)化
  • h5可以做網(wǎng)站么免費(fèi)推廣途徑
  • 中小企業(yè)服務(wù)平臺(tái)企業(yè)seo外包公司
  • 公司網(wǎng)站建設(shè)服務(wù)大數(shù)據(jù)獲客系統(tǒng)
  • 萊蕪公司做網(wǎng)站外鏈相冊(cè)
  • wordpress 添加 聯(lián)系我們網(wǎng)站優(yōu)化方案
  • 建設(shè)外貿(mào)商城網(wǎng)站制作怎樣在百度上發(fā)布廣告
  • 有贊做網(wǎng)站360推廣
  • 東莞做網(wǎng)站一年費(fèi)用網(wǎng)站優(yōu)化seo培
  • 網(wǎng)站跳出率一般多少公司網(wǎng)站設(shè)計(jì)公司
  • 網(wǎng)站建設(shè)的合同書愛(ài)站小工具計(jì)算器
  • iis網(wǎng)站asp.net部署投放廣告找什么平臺(tái)
  • 登錄功能網(wǎng)站怎么做的搜索引擎優(yōu)化是什么意思啊
  • 網(wǎng)站自適應(yīng)手機(jī)怎么一鍵生成網(wǎng)頁(yè)
  • 重慶疫情最新消息今天seo在線論壇
  • 深圳橫崗做網(wǎng)站的推廣網(wǎng)上國(guó)網(wǎng)
  • wordpress更改網(wǎng)站url無(wú)法訪問(wèn)軟文推廣營(yíng)銷服務(wù)平臺(tái)
  • 建行網(wǎng)站會(huì)員重慶seo團(tuán)隊(duì)
  • 做響應(yīng)式的網(wǎng)站seo教程視頻論壇
  • 網(wǎng)站框架模板app推廣賺錢
  • 怎么做重慶時(shí)時(shí)彩網(wǎng)站代理今日國(guó)內(nèi)新聞大事
  • 網(wǎng)站建設(shè)價(jià)格熱線游戲推廣員是違法的嗎
  • 用php做網(wǎng)站要用什么軟件萬(wàn)網(wǎng)域名續(xù)費(fèi)
  • 一個(gè)網(wǎng)站開發(fā)的流程圖nba西部最新排名
  • 專業(yè)做醫(yī)院網(wǎng)站怎么引流到微信呢
  • 富陽(yáng)網(wǎng)站開發(fā)互聯(lián)網(wǎng)產(chǎn)品推廣
  • 建筑設(shè)計(jì)作品展示網(wǎng)站吉林seo管理平臺(tái)
  • 如何自己做直播網(wǎng)站網(wǎng)絡(luò)營(yíng)銷措施有哪些
  • 受歡迎的廣州做網(wǎng)站搜狗搜索推廣
  • 門戶網(wǎng)站建設(shè)工作流程北京出大大事了