Chinaunix首页 | 论坛 | 博客
  • 博客访问: 600426
  • 博文数量: 165
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1554
  • 用 户 组: 普通用户
  • 注册时间: 2013-10-23 22:57
个人简介

我本仁慈,奈何苍天不许

文章分类

全部博文(165)

文章存档

2018年(1)

2016年(33)

2015年(5)

2014年(34)

2013年(92)

分类: LINUX

2013-12-26 16:55:49

【实验平台】

主机:Ubuntu 10.10

目标机:FS_S5PC100

目标机内核版本:2.6.35

交叉编译器版本:arm-none-linux-gnueabi-gcc-4.5.1

【实验步骤】

注意:在实验过程中"$"后的操作在主机上,"#"后的操作在开发板上

一、需要在下面目录下修改Kconfig文件,在里面加上红色字体这句话

 config I2C_S3C2410

        tristate "S3C2410 I2C Driver"

         depends on ARCH_S3C2410 || ARCH_S3C64XX || ARCH_S5PC100

         help

           Say Y here to include support for I2C controller in the

          Samsung S3C2410 based System-on-Chip devices.

/home/farsight/kernel/linux-2.6.35-farsight/drivers/i2c/busses

内核配置并重新编译内核

$ make menuconfig

Device Drivers  --->

<*> I2C support  --->

<*>   I2C device interface

I2C Hardware Bus support  --->

<*> S3C2410 I2C Driver

$ make zImage

二、使用内核i2c子系统构建驱动

1、 修改平台代码并重新编译内核

修改arch/arm/mach-s5pc100/mach-smdkc100.c

修改:

static struct i2c_board_info i2c_devs0[] __initdata = {

};

为:

static struct i2c_board_info i2c_devs0[] __initdata = {

{

I2C_BOARD_INFO("lm75", 0x48),

},

};

$ make zImage

2、  拷贝模块到linux

将实验代码中的s5pc100_temp拷贝到/home/linux目录下并进入s5pc100_temp目录。

3、 编译模块

$ make

4、 编译应用程序

$ arm-none-linux-gnueabi-gcc test.c o test

5、 拷贝驱动及应用程序到目标板上

$ cp s5pc100_temp.ko test /source/rootfs

6、 启动开发板后加载模块

# insmod s5pc100_temp.ko

7、 创建设备节点

# mknod /dev/lm75 c 250 0   //这里创建的设备文件名只需要跟测试程序里面打开的问价名一样即可,不必和加载进内核的驱动名相同

8、 测试

# ./test 

这个值是16进制数,前两位代表度,后两位是小数点后的值,大家可以自己转换一下

驱动代码:

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

MODULE_LICENSE ("GPL");

#define LM75_REG_CONF 0x01

static const u8 LM75_REG_TEMP[3] = {

0x00, /* input */

0x03, /* max */

0x02, /* hyst */

};

struct lm75_data 

{

u16 temp[3]; /* Register values,

   0 = input

   1 = max

   2 = hyst */

};

static int lm75_major = 250;

static int lm75_minor = 0;

static int number_of_devices = 1;

static dev_t devno = 0;

static struct cdev cdev;

static struct i2c_client *new_client;

struct lm75_data *data;

static int lm75_read_value(struct i2c_client *client)

{

struct i2c_msg msgs[2];

int status;

char buf1[2];

char buf2[2];

msgs[0].len = 1;

msgs[0].addr = client->addr; // lm75 设备地址

msgs[0].flags = 0;//write

msgs[0].buf = buf1;

msgs[0].buf[0] = LM75_REG_TEMP[0];

msgs[1].len = 2;//读出的数据

msgs[1].addr = client->addr;// lm75 设备地址 

msgs[1].flags = I2C_M_RD;//read

msgs[1].buf = buf2;//存放返回值的地址。

status = i2c_transfer(client->adapter, msgs, 2);

if(status < 0)

return status;

// printk("1 = %2x %2x\n", buf2[0], buf2[1]);

return (buf2[0] << 8) | buf2[1];

}

static ssize_t lm75_read(struct file *file, char __user *buff, size_t count, loff_t *offset) 

{

int status;

status = lm75_read_value(new_client);

if(status < 0)

{

return status;

}

printk("status = %x\n", status);

if(copy_to_user(buff, (char *)&status, sizeof(status)))

return -EFAULT;

return 0;

}

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

{

return 0;

}

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

{

return 0;

}

static struct file_operations lm75_fops = {

.owner  = THIS_MODULE,

.read = lm75_read,

.open  = lm75_open,

.release = lm75_release,

};

static int lm75_probe(struct i2c_client *client, const struct i2c_device_id *id)

{

int ret = 0;

new_client = client;

if (!i2c_check_functionality(client->adapter,

I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))

return -EIO;

data = kzalloc(sizeof(struct lm75_data), GFP_KERNEL);

if (!data)

return -ENOMEM;

i2c_set_clientdata(client, data);

devno = MKDEV(lm75_major, lm75_minor);

ret = register_chrdev_region(devno, number_of_devices, "lm75");

if(ret)

{

printk("failed to register device number\n");

goto err_register_chrdev_region;

}

cdev_init(&cdev, &lm75_fops);

cdev.owner = THIS_MODULE;

ret = cdev_add(&cdev, devno, number_of_devices);

if(ret)

{

printk("failed to add device\n");

goto err_cdev_add;

}

return 0;

err_cdev_add:

unregister_chrdev_region(devno, number_of_devices);

err_register_chrdev_region:

kfree(data);

return ret;

}

static int lm75_remove(struct i2c_client *client)

{

cdev_del(&cdev);

unregister_chrdev_region(devno, number_of_devices);

return 0;

}

enum lm75_type { /* keep sorted in alphabetical order */

lm75,

lm75a,

};

static const struct i2c_device_id lm75_ids[] = {

{ "lm75", lm75, },

{ "lm75a", lm75a, },

{ /* LIST END */ }

};

static struct i2c_driver lm75_driver = {

.driver = {

.name = "lm75",

},

.probe  = lm75_probe,

.remove  = lm75_remove,

.id_table = lm75_ids,

};

static int __init s5pc100_lm75_init(void)

{

return i2c_add_driver(&lm75_driver);

}

static void __exit s5pc100_lm75_exit(void)

{

i2c_del_driver(&lm75_driver);

}

module_init(s5pc100_lm75_init);

module_exit(s5pc100_lm75_exit);

测试代码:

#include 

#include 

#include 

#include 

#include 

int main (void) 

{

int fd;

int data;

fd = open ("/dev/lm75",O_RDWR);

if (fd < 0) {

perror("open");

exit(0);

}

while(1)

{

read (fd, (char *)&data, sizeof(data));

sleep(1);

printf("%x\n", data);

}

close (fd);

printf ("/dev/temp closed :)\n");

return 0;

}

Makefile

ifeq ($(KERNELRELEASE),)

KERNELDIR ?= /home/farsight/kernel/linux-2.6.35-farsight

CC = /opt/toolchain/arm-none-linux-gnueabi-gcc

PWD := $(shell pwd)

modules:

$(MAKE) -C $(KERNELDIR) M=$(PWD) modules

modules_install:

$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install

test:test.c

clean:

rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions Module* module* test

.PHONY: modules modules_install clean

else

    obj-m := s5pc100_temp.o

endif

阅读(1419) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~