Linux驱动开发、19-I2C子系统之客户驱动分析与移植

来源:互联网 发布:赛维网络加班严重吗 编辑:程序博客网 时间:2024/06/06 00:30

I2C子系统_设备驱动移植

 

 

用户程序通过I2C设备驱动程序访问步骤是这样的...

 

用户的操作函数---/sys/bus/i2c/devices/....->设备驱动的操作函数---->最终回调i2c-core的函数实现数据的通信。

 

AT24.C驱动追踪:(Linux内核已经帮我们实现大部分驱动,所以驱动开发移植比较多..

 

模块入口:每个i2c设备都需要使用该函数向i2c总线注册。

i2c_add_driver(&at24_driver); /*添加设备驱动,将驱动挂载在I2C总线上*/

 

/*i2c_driver是一种平台设备*/

static struct i2c_driver at24_driver = {

.driver = {

.name = "at24",

.owner = THIS_MODULE,

},

.probe = at24_probe,

.remove = __devexit_p(at24_remove),

.id_table = at24_ids, /*设备驱动所支持的设备型号列表*/

};

继续查看 prob 函数:

struct at24_platform_data chip;  /*用这个结构获取定义在/arch/arm/match-xxx/...平台初始化设备*/

 

之后对选取芯片进一步检测

 

接着:sysfs_bin_attr_init(&at24->bin);  初始化属性文件

at24->bin.attr.name = "eeprom";

sysfs_create_bin_filesys/.../eeprom二进制文件,并绑定相关的操作函数

 

at24->bin.attr.mode = chip.flags & AT24_FLAG_IRUGO ? S_IRUGO : S_IRUSR; /*文件权限*/

at24->bin.read = at24_bin_read; /*对文件进行读操作*/

at24->bin.write = at24_bin_write; /*对文件写*/

 

从这里可以看出,通过读写sys/.../eeprom 设备文件从而达到通讯的目的

具体在进来写看看

 

/*

 * Note that if the hardware write-protect pin is pulled high, the whole

 * chip is normally write protected. But there are plenty of product

 * variants here, including OTP fuses and partial chip protect.

 *

 * We only use page mode writes; the alternative is sloooow. This routine

 * writes at most one page.

 */

static ssize_t at24_eeprom_write(struct at24_data *at24, const char *buf,

unsigned offset, size_t count)

{

struct i2c_client *client;

struct i2c_msg msg;

ssize_t status;

unsigned long timeout, write_time;

unsigned next_page;

 

/* Get corresponding I2C address and adjust offset */

client = at24_translate_offset(at24, &offset);

 

/* write_max is at most a page */

if (count > at24->write_max)

count = at24->write_max;

 

/* Never roll over backwards, to the start of this page */

next_page = roundup(offset + 1, at24->chip.page_size);

if (offset + count > next_page)

count = next_page - offset;

 

/* If we'll use I2C calls for I/O, set up the message,构造消息,和用户驱动一样的*/

if (!at24->use_smbus) {

int i = 0;

 

msg.addr = client->addr;

msg.flags = 0;

 

/* msg.buf is u8 and casts will mask the values */

msg.buf = at24->writebuf;

if (at24->chip.flags & AT24_FLAG_ADDR16)

msg.buf[i++] = offset >> 8;

 

msg.buf[i++] = offset;

memcpy(&msg.buf[i], buf, count);

msg.len = i + count;

}

 

/*

 * Writes fail if the previous one didn't complete yet. We may

 * loop a few times until this one succeeds, waiting at least

 * long enough for one entire page write to work.

 */

timeout = jiffies + msecs_to_jiffies(write_timeout);

do {

write_time = jiffies;

if (at24->use_smbus) {

status = i2c_smbus_write_i2c_block_data(client,

offset, count, buf);

if (status == 0)

status = count;

} else {

/*数据发送给控制器去处理进而实现数据通讯,所以它还是经过了控制器的*/

status = i2c_transfer(client->adapter, &msg, 1);/*来源于I2C-CORE*/

if (status == 1)

status = count;

}

dev_dbg(&client->dev, "write %zu@%d --> %zd (%ld)\n",

count, offset, status, jiffies);

 

if (status == count)

return count;

 

/* REVISIT: at HZ=100, this is sloooow */

msleep(1);

} while (time_before(write_time, timeout));

 

return -ETIMEDOUT;

}

 

 

 

i2c设备注册

TQ210上移植AT24C02设备驱动:需要用到的....

 

1、每个开发板在 /arch/arm/mach-xxx 中有一个mach-xxx.c 这个文件记录了开发板上存在的设备资源!

2、因为内核集成了AT24驱动,平台驱动要对应平台设备,所以使用驱动前应该注册平台设备。I2C平台设备注册需要用到函数:

 

i2c_register_board_info(int busnum,struct i2c_board_info const *info, unsigned len)

参数说明:

busnum:指明用到那条i2c总线,TQ210支持4I2C总线

struct i2c_board_info const *info: i2c设备描述符

len: 设备描述符的大小

 

详细注册信息:

 

 

照着别人的来改

 

/* I2C0 */

//add by hntea

#include<linux/i2c/at24.h>

 

static struct at24_platform_data at24c02=

{

.byte_len = 2048/8,

.page_size = 8,

.flags = 0

};

static struct i2c_board_info i2c_devs0[] __initdata = {

#ifdef CONFIG_SND_SOC_WM8960_TQ210

{

I2C_BOARD_INFO("wm8960", 0x1a),

.platform_data  = &wm8960_pdata,

},

#endif

#ifdef CONFIG_SND_SOC_WM8580

{

I2C_BOARD_INFO("wm8580", 0x1b),

},

#endif

//add by hntea

{

I2C_BOARD_INFO("24c02", 0x50), /*这个文件名要和驱动对应*/

.platform_data  = &at24c02,

},

};

修改完后将驱动编入内核

 

 

 


从新编译一下内核就好了.

 

注册使用

i2c_register_board_info(0, i2c_devs0, ARRAY_SIZE(i2c_devs0));

 

以上这幅图很明显没有产生eeprom 文件....

原因在于I2C_BOARD_INFO("at24c02", 0x50), /*这个文件名要和驱动对应*/

设备名写错了,导致驱动在列表中找不到对应的设备号

 

 

3、测试驱动是否有效....

 

驱动测试

#include<stdio.h>

#include<sys/fcntl.h>

#include<sys/types.h>

 

 

#define PATH "/sys/bus/i2c/devices/0-0050/eeprom"

int main(void)

{

int fd = 0;

int ret = 0;

unsigned char i=0;  

 char readData[12],wrData[12];

/*1、打开设备文件*/

if( (fd = open(PATH,O_RDWR) )<0 )

printf("open err!\n fd = %d \n",fd);

/*2、文件定位*/

lseek(fd,0,SEEK_SET);

/*3、写入数据*/

for(i=0;i<12;i++)

{

wrData[i]=i;

}

if ((ret = write(fd,wrData,12))<0)

printf("wr err!\n");

lseek(fd,0,SEEK_SET);

/*4、读取数据*/

if ((ret = read(fd,readData,12))<0)

printf("rd  err!\n");

 

/*5、打印数据*/

for(i=0;i<12;i++)

{

printf("%d\n",readData[i]);

 

}

/*5、关闭文件*/

close(fd);

}


大功告成!

0 0
原创粉丝点击