1. 程式人生 > >linux IIC子系統分析(九)——例項分析通過裝置節點訪問I2c裝置

linux IIC子系統分析(九)——例項分析通過裝置節點訪問I2c裝置

《 linux IIC子系統分析(四)——I2c bus初始化》 中我們建立了I2C 匯流排驅動,I2C adapter device 和adapter drivers也在這時建立

在我們實際開發中,I2C 匯流排驅動一般晶片原廠會提供,我們開發一般是設計裝置驅動。

在訪問I2C裝置驅動的方法中:

通過i2c-dev 從應用層驅動裝置,這樣的設計需要對I2C通訊協議非常熟悉,一般比較少使用。

通過sysfs匯出的bin屬性檔案訪問,這種方法多用了檢視驅動裝置的資訊,實際使用它來操作裝置較少。

下面介紹一種比較通用客戶驅動程式開發的方法,其開發步驟為:

(1)註冊板載I2C裝置資訊

(2)定義I2C驅動ID

(3)定義i2c_driver結構並完成其相應的函式

(4)模組初始化時新增/撤銷時刪除i2c_driver

(5)新增裝置節點,sysfs bin屬性

註冊板載I2C資訊,與上一章相同在/linux-2.6.32.2/arch/arm/mach-s3c2440/math-mini2440.c中新增:

#include <linux/i2c/at24.h>
#include <linux/i2c.h>
static struct s3c24xx_mci_pdata mini2440_mmc_cfg = {
   .gpio_detect   = S3C2410_GPG(8),
   .gpio_wprotect = S3C2410_GPH(8),
   .set_power     = NULL,
   .ocr_avail     = MMC_VDD_32_33|MMC_VDD_33_34,
};


static struct at24_platform_data at24c02 = {
	.byte_len	= SZ_2K / 8,
	.page_size	= 8,
	.flags		= 0,
};

static struct i2c_board_info __initdata smdk_i2c_devices[] = {
	/* more devices can be added using expansion connectors */
	{
		I2C_BOARD_INFO("24c02", 0x50),
		.platform_data = &at24c02,
	},
};

在函式static void __init mini2440_machine_init(void) 中新增:
i2c_register_board_info(0, smdk_i2c_devices, ARRAY_SIZE(smdk_i2c_devices));

新增驅動程式如下:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <linux/smp_lock.h>
#include <linux/jiffies.h>
#include <asm/uaccess.h>
#include <linux/delay.h>


#define DEBUG 1
#ifdef DEBUG
#define dbg(x...) printk(x)
#else 
#define dbg(x...) (void)(0)
#endif

#define I2C_MAJOR 89
#define DEVICE_NAME "at24c02"
static struct class *my_dev_class;
static struct i2c_client *my_client;
static struct i2c_driver my_i2c_driver;


static struct i2c_device_id my_ids[] = {
	{"24c01",0x50},
	{"24c02",0x50},
	{"24c08",0x50},
	{}
};

MODULE_DEVICE_TABLE(i2c,my_ids);

static int my_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
	int res;
	struct device *dev;

	dbg("probe:name = %s,flag =%d,addr = %d,adapter = %d,driver = %s\n",client->name,
		 client->flags,client->addr,client->adapter->nr,client->driver->driver.name );

	dev = device_create(my_dev_class, &client->dev,
				     MKDEV(I2C_MAJOR, 0), NULL,
				     DEVICE_NAME);
	if (IS_ERR(dev))
	{
		dbg("device create error\n");
		goto out;
	}
	my_client = client;
	
	return 0;
out:
	return -1;
}
static int  my_i2c_remove(struct i2c_client *client)
{

	dbg("remove\n");
	return 0;
}

static ssize_t at24c02_read(struct file *fd, char *buf, ssize_t count, loff_t *offset)
{
	char *tmp;
	int ret;
	char data_byte;
	char reg_addr = 0,i;
	struct i2c_client *client = (struct i2c_client*) fd->private_data;
	struct i2c_msg msgs[2];

	dbg("read:count = %d,offset = %ld\n",count,*offset);
	tmp = kmalloc(count,GFP_KERNEL);

	if (!tmp)
	{
		dbg("malloc error in read function\n");
		goto out;
	}

	reg_addr = *offset;
	msgs[0].addr = client->addr;
	msgs[0].flags = client->flags & (I2C_M_TEN|I2C_CLIENT_PEC) ;
	msgs[0].len = 1;
	msgs[0].buf = (char *)®_addr;
	
	msgs[1].addr= client->addr;
	msgs[1].flags = client->flags & (I2C_M_TEN|I2C_CLIENT_PEC);
	msgs[1].flags |= I2C_M_RD;
	msgs[1].len = count;
	msgs[1].buf = (char*)tmp;

	ret = i2c_transfer(client->adapter,&msgs,2);
	if (ret != 2)
		goto out;
	if (copy_to_user(buf, tmp, count))
		goto out;
	
	kfree(tmp);
	return count;
out:
	kfree(tmp);
	return -1;	
	
}


static int at24c02_ioctl(struct file *fd, unsigned int cmd, unsigned long arg)
{
	dbg("ioctl code ...\n");
	return 0;
}

static ssize_t at24c02_write(struct file *fd, char *buf, ssize_t count, loff_t *offset)
{
	int ret,i;
	char *tmp;
	int errflg;
	struct i2c_msg msg;
 	struct i2c_client *client = (struct i2c_client*) fd->private_data;
	char tmp_data[2];

 	dbg("write:count = %d,offset = %ld\n",count,*offset);
	tmp = kmalloc(count, GFP_KERNEL);
	if (!tmp)
		goto out;
	if (copy_from_user(tmp, buf, count))
		goto out;
	msg.addr = client->addr;
	msg.flags = client->flags & (I2C_M_TEN | I2C_CLIENT_PEC);
	for (i = 0; i < count; i++) {
		msg.len = 2;
		tmp_data[0] = *offset + i;
		tmp_data[1] = tmp[i];
		msg.buf = tmp_data;
		ret = i2c_transfer(client->adapter,&msg,1);
		if (ret != 1)
			goto out;
		msleep(1);
	} 
	kfree(tmp);

	return ((ret == 1) ? count:ret);
out:
	kfree(tmp);
	return -1;
	
}
static int at24c02_open(struct inode *inode, struct file *fd)
{

	fd->private_data =(void*)my_client;
	return 0;

}

static int at24c02_release(struct inode *inode, struct file *fd)
{
	dbg("release\n");
	fd->private_data = NULL;
	
	return 0;	

}

static const struct file_operations i2c_fops = {
	.owner = THIS_MODULE,
	.open 	= at24c02_open,
	.read  = at24c02_read,
	.write = at24c02_write,
	.unlocked_ioctl = at24c02_ioctl,
	.release = at24c02_release,
};

static struct i2c_driver my_i2c_driver = {
	.driver = {
		.name = "i2c_demo",
		.owner = THIS_MODULE,
	},
	.probe = my_i2c_probe,
	.remove = my_i2c_remove,
	.id_table = my_ids,
};

static int __init my_i2c_init(void)
{
	int res;
	
	
	res = register_chrdev(I2C_MAJOR,DEVICE_NAME,&i2c_fops);
	if (res)
	{
		dbg("register_chrdev error\n");
		return -1;
	}
	my_dev_class = class_create(THIS_MODULE, DEVICE_NAME);
	if (IS_ERR(my_dev_class))
	{
		dbg("create class error\n");
		unregister_chrdev(I2C_MAJOR, DEVICE_NAME);
		return -1;
	}
	return i2c_add_driver(&my_i2c_driver);
}

static void __exit my_i2c_exit(void)
{
	unregister_chrdev(I2C_MAJOR, DEVICE_NAME);
	class_destroy(my_dev_class);
	i2c_del_driver(&my_i2c_driver);
	
}

MODULE_AUTHOR("itspy<
[email protected]
>"); MODULE_DESCRIPTION("i2c client driver demo"); MODULE_LICENSE("GPL"); module_init(my_i2c_init); module_exit(my_i2c_exit);

將驅動程式編譯成驅動模組新增到核心,可以檢視到:
[[email protected] i2c-0]# ls
0-0050         name           subsystem
delete_device  new_device     uevent
[[email protected] i2c-0]# cd 0-0050/
[[email protected] 0-0050]# ls
at24c02    driver     modalias   name       subsystem  uevent
[[email protected] 0-0050]# pwd
/sys/devices/platform/s3c2440-i2c/i2c-0/0-0050
[[email protected] 0-0050]# ls /dev -l
crw-rw----    1 root     root      10,  59 Jan  1  2000 adc
crw-rw----    1 root     root      89,   0 Jan  1 01:14 at24c02
crw-rw----    1 root     root      14,   4 Jan  1  2000 audio

這樣就可以與正常驅動裝置一樣操作eeprom了。

相關推薦

linux IIC子系統分析()——例項分析通過裝置節點訪問I2c裝置

在《 linux IIC子系統分析(四)——I2c bus初始化》 中我們建立了I2C 匯流排驅動,I2C adapter device 和adapter drivers也在這時建立在我們實際開發中,I2C 匯流排驅動一般晶片原廠會提供,我們開發一般是設計裝置驅動。在訪問I2

linux IIC子系統分析(二)—— linux i2c 架構概述

I2C匯流排因為它及簡單的硬體連線和通訊方式,在現在的很多裝置上它是一種不可或缺的通訊匯流排。如果用當微控制器直接操作I2C,其實很簡單,只要正確把握IIC的操作時序就可以了。但是在linux系統中,I

linux IIC子系統分析(四)——I2c bus初始化

這裡的I2C Bus 並不是通訊上的匯流排,而是linux系統為了管理裝置和驅動而虛擬出來的,在I2C Bus用來掛載後面將會使用到的I2C 介面卡(adapter)和I2C裝置(client)。另外,

Linux input子系統編程、分析與模板

linux輸入設備都有共性:中斷驅動+字符IO,基於分層的思想,Linux內核將這些設備的公有的部分提取出來,基於cdev提供接口,設計了輸入子系統,所有使用輸入子系統構建的設備都使用主設備號13,同時輸入子系統也支持自動創建設備文件,這些文件采用阻塞的IO讀寫方式,被創建在"/dev/input/"下。如下

Linux網路驅動程式開發例項分析

一.Linux系統裝置驅動程式概述   1.1 Linux裝置驅動程式分類   1.2 編寫驅動程式的一些基本概念 二.Linux系統網路裝置驅動程式 2.1 網路驅動程式的結構 2.2 網路驅動程式的基本方法 2.3 網路驅動程式中用到的資料結構 2.4 常用的系統支援 

Linux\Unix IPC程序通訊例項分析(一):共享記憶體通訊---系統V

前些天看到有個博主寫部落格採用問答式的敘述方法:把很多知識點通過一問一答的形式把文章串起來,我覺得這種形式不錯,便於突出重點。後面我也做下嘗試,一邊寫寫部落格,一邊回顧一下自己對IPC程序通訊的認識。 Q:這些例子來自哪? Q:IBM原文都寫過了,為什麼還要在這裡再寫一

Oracle 多例項如何通過EM進行訪問

單臺Oracle資料庫如果建立了多例項,如何通過EM進行訪問呢? 預設EM只會訪問第一個例項,那其他的例項呢? 那我們一起來看下這個檔案就會明白了 ORACLE_HOME/install/portlist.ini -----------------------------------------------

Linux裝置驅動篇——[I2C裝置驅動-1]

i2c-dev.c中提供i2cdev_read()、i2cdev_write()函式來對應使用者空間要使用的read()和write()檔案操作介面,這兩個函式分別呼叫I2C核心的i2c_master_recv()和i2c_master_send()函式來構造一條I2C訊息並引發介面卡algorithm通訊函

Linux裝置驅動入門----I2C裝置驅動

/* * I2C驅動的一些模板: * (1)、I2C匯流排驅動的的模組載入和解除安裝函式模板 * (2)、I2C匯流排通訊方法 * (3)、I2C裝置驅動模組的載入和解除安裝 * (4)、I2C裝置驅動的檔案操作介面 * (與普通驅動的檔案操作一致,

Linux時間子系統(十七) ARM generic timer驅動代碼分析

detect led 直接 系統啟動 value lsp func 多核 borde 一、前言 關註ARM平臺上timer driver(clocksource chip driver和clockevent chip driver)的驅動工程師應該會註意到timer硬件的演

linux input輸入子系統分析《四》:input子系統整體流程全面分析

總線 返回值 分代 並不是 事件 等等 lag pri 位置 1 input輸入子系統整體流程 本節分析input子系統在內核中的實現,包括輸入子系統(Input Core),事件處理層(Event Handler)和設備驅動層。由於上節代碼講解了設備驅動層的寫法

i2c子系統-eeprom例項分析

兩種訪問eeprom的例子 在Linux應用層訪問eeprom的方法,並給出示例程式碼方便大家理解。第一個方法是通過eeprom的裝置檔案進行訪問。這兩個方法分別對應了i2c裝置驅動的兩個不同的實現,第二個方法是通過sysfs檔案系統對eeprom進行訪問。 第一種通過devfs

(轉)linux kernel socket例項分析

#include <asm/atomic.h> #include <asm/checksum.h> #include <asm/unaligned.h> #include <linux/module.h> #include

Linux IIO子系統分析-1-概述

http://blog.chinaunix.net/uid-20543672-id-2976189.html 分類: LINUX2011-10-20 15:33:25 最近稍微看了下LKML,發現裡面有一個子系統叫做“IIO”。以前沒有接觸過,所以Google了下。 IIO子系統全稱是 In

Linux 輸入子系統分析 Linux之輸入子系統分析(詳解)

為什麼要引入輸入子系統? 在前面我們寫了一些簡單的字元裝置的驅動程式,我們是怎麼樣開啟一個裝置並操作的呢? 一般都是在執行應用程式時,open一個特定的裝置檔案,如:/dev/buttons 1 ..... 2 int main(int argc, char **argv) 3 {

轉《Linux input子系統分析之一:軟體層次》

本文轉自:https://blog.csdn.net/yueqian_scut/article/details/47903853 輸入輸出是使用者和產品互動的手段,因此輸入驅動開發在Linux驅動開發中很常見。同時,input子系統的分層架構思想在Linux驅動設計中極

Linux-Flash驅動(2)-塊裝置驅動例項分析

在上一節課中,我們在記憶體中劃分出512kB作為一個塊裝置,並對它實現讀寫的操作。現在我們來具體分析這段程式碼。 #include <linux/module.h> #include <linux/moduleparam.h> #include

linux驅動由淺入深系列:高通sensor架構例項分析之一

本系列導航: 最初的時候晶片廠家對sensor的處理和對待其它外設一樣都是直接掛在processor上,sensor的驅動也和其他linux或android的驅動一樣,生成對應的裝置節點給上層提供資料(關於此類linux基礎驅動的知識,可以參考本部落格其他博文)

Linux ALSA音訊框架分析二:linux音訊子系統介紹

   Phonon是KDE 4的多媒體API 。Phonon提供一個穩定的API允許KDE 4獨立於任何一個聲音系統伺服器如xine。Phonon讓各種後端提供介面給開發者所謂的"引擎";每個引擎運作在一個具體的後端。每個後端都可讓Phonon控制基本功能,如播放、暫停和搜尋。Phonon也支援更高層次的功能

linux select與poll實現機制與例項分析

    我們直到上層對檔案操作結合select與poll可以實現阻塞操作,那麼究竟是如何實現的呢? select介面:     int select(int nfds, fd_set *readset, fd_set *writeset,                fd