与前面普通设备驱动1方法不同,这里的普通设备驱动利用i2c-core.c提供的i2c_transfer方法来实现设备驱动,
而不是普通设备驱动1里面的通过操纵s3c2440的i2c寄存器来与设备通信
一、采用友善之臂的2.6.32.2内核,需要修改/linux-2.6.32.2/arch/arm/mach-s3c2440/mach-mini2440.c文件
1)添加 #include
2)在static struct platform_device *mini2440_devices[]前添加struct i2c_board_info i2c_devices[]结构体
-
-
static struct i2c_board_info i2c_devices[] __initdata={
-
{I2C_BOARD_INFO("at24c08", 0x50), },
-
};
-
-
static struct platform_device *mini2440_devices[] __initdata = {
-
&s3c_device_usb,
-
&s3c_device_rtc,
-
&s3c_device_lcd,
-
&s3c_device_wdt,
-
&s3c_device_i2c0,
-
&s3c_device_iis,
-
&mini2440_device_eth,
-
&s3c24xx_uda134x,
-
&s3c_device_nand,
-
&s3c_device_sdi,
-
&s3c_device_usbgadget,
-
};
3)在mini2440_machine_init(void)函数内添加i2c_register_board_info(0,i2c_devices,ARRAY_SIZE(i2c_devices));函数
-
static void __init mini2440_machine_init(void)
-
{
-
i2c_register_board_info(0,i2c_devices,ARRAY_SIZE(i2c_devices));
-
-
#if defined (LCD_WIDTH)
-
s3c24xx_fb_set_platdata(&mini2440_fb_info);
-
#endif
-
s3c_i2c0_set_platdata(NULL);
-
-
s3c2410_gpio_cfgpin(S3C2410_GPC(0), S3C2410_GPC0_LEND);
-
-
s3c_device_nand.dev.platform_data = &friendly_arm_nand_info;
-
s3c_device_sdi.dev.platform_data = &mini2440_mmc_cfg;
-
platform_add_devices(mini2440_devices, ARRAY_SIZE(mini2440_devices));
-
s3c_pm_init();
-
}
二、在linux2.6.32.2/drivers/i2c/chips/目录下添加at24c08.c设备驱动文件,并对应的修改Kconfig和Makefile文件
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
-
#define major 155
-
static struct i2c_driver at24c08_driver;
-
static struct i2c_adapter *at24c08_adapter;
-
static unsigned short addr;
-
static struct class at24c08_cls = {
-
.name = "at24c08_cls",
-
};
-
-
ssize_t at24c08_read (struct file *filp, char __user *buf, size_t sz, loff_t *off)
-
{
-
struct i2c_msg msg[2];
-
unsigned char args, data;
-
-
if (sz != 1)
-
return -EINVAL;
-
copy_from_user((void *)&args, buf, 1);
-
-
msg[0].addr = addr;
-
msg[0].buf = &args;
-
msg[0].len = 1;
-
msg[0].flags = 0;
-
-
-
msg[1].addr = addr;
-
msg[1].buf = &data;
-
msg[1].len = 1;
-
msg[1].flags = 1;
-
if (2 == i2c_transfer(at24c08_adapter, msg, 2)) {
-
-
copy_to_user((void *)buf, &data, 1);
-
return 1;
-
}
-
else
-
return -EIO;
-
}
-
-
ssize_t at24c08_write (struct file *filp, const char __user *buf, size_t sz, loff_t *off)
-
{
-
struct i2c_msg msg;
-
unsigned char args[2];
-
-
copy_from_user((void *)&args, buf, 2);
-
-
-
msg.addr = addr;
-
msg.buf = args;
-
msg.len = 2;
-
msg.flags = 0;
-
if(1 == i2c_transfer(at24c08_adapter,&msg, 1))
-
return 2;
-
else
-
return -EIO;
-
-
}
-
-
static struct file_operations at24c08_fops = {
-
.owner = THIS_MODULE,
-
.read = at24c08_read,
-
.write = at24c08_write,
-
};
-
-
static struct cdev cdev;
-
static int at24c08_probe(struct i2c_client *client, const struct i2c_device_id *dev_id)
-
{
-
register_chrdev_region(major, 1, "at24c08");
-
cdev_init(&cdev, &at24c08_fops);
-
cdev_add(&cdev, MKDEV(major, 0), 1);
-
class_register(&at24c08_cls);
-
device_create(&at24c08_cls, NULL, MKDEV(major, 0), NULL, "at24c08_dev");
-
return 0;
-
}
-
-
static int at24c08_remove(struct i2c_client *client)
-
{
-
device_destroy(&at24c08_cls, MKDEV(major, 0));
-
class_destroy(&at24c08_cls);
-
cdev_del(&cdev);
-
unregister_chrdev_region(MKDEV(major, 0), 1);
-
-
return 0;
-
}
-
-
static int at24c08_detect(struct i2c_client *client, int kind, struct i2c_board_info *bd_info)
-
{
-
strcpy(bd_info->type, "at24c08");
-
addr = bd_info->addr = client->addr;
-
at24c08_adapter = client->adapter;
-
return 0;
-
}
-
-
static const struct i2c_device_id at24c08_id[] = {
-
{"at24c08", 0},
-
{}
-
};
-
-
static unsigned short ignore[] = { I2C_CLIENT_END };
-
-
static const unsigned short normal_i2c[] = {0x50, I2C_CLIENT_END};
-
-
static const struct i2c_client_address_data addr_data = {
-
.normal_i2c = normal_i2c,
-
.probe = ignore,
-
.ignore = ignore,
-
};
-
static struct i2c_driver at24c08_driver= {
-
.probe = at24c08_probe,
-
.remove = at24c08_remove,
-
.driver = {
-
.name = "at24c08",
-
},
-
.id_table = at24c08_id,
-
.detect = at24c08_detect,
-
.address_data = &addr_data,
-
.class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
-
};
-
-
static int at24c08_init(void)
-
{
-
i2c_add_driver(&at24c08_driver);
-
return 0;
-
}
-
-
static void at24c08_exit(void)
-
{
-
i2c_del_driver(&at24c08_driver);
-
return ;
-
}
-
-
module_init(at24c08_init);
-
module_exit(at24c08_exit);
-
MODULE_LICENSE("GPL");
-
MODULE_AUTHOR("100ask.net Young");
以上要说明的是为什么insmod at24c08.ko之后会在/dev/目录下自动创建/dev/at24c08_dev文件节点
主要归功于两个函数
static struct class at24c08_cls = { .name = "at24c08_cls", };
class_register(&at24c08_cls);
device_create(&at24c08_cls, NULL, MKDEV(major, 0), NULL, "at24c08_dev");
内核中定义了struct class结构体,顾名思义,一个struct class结构体类型变量对应一个类,内核同时提供了class_create(…)函数,
可以用它来创建一个类,这个类存放于sysfs下面,一旦创建好了这个类,再调用device_create(…)函数来在/dev目录下创建相应的
设备节点。这样,加载模块的时候,用户空间中的udev会自动响应device_create(…)函数,去/sysfs下寻找对应的类从而创建设备节点。
与class_create等价的函数是class_register,只是他们对应的注销函数不同class_unregister和class_destory。
三、在linux2.6.32.2目录下make menuconfig进行内核定制之后再make则会生成i2c-core.ko,i2c-s3c2440.ko,at24c08.ko等文件,
将三个文件都insmod到内核中,在/dev/目录下会自动生成at24c08_dev文件节点,但是在重启之后会消失,因为insmod是动态加载的,
如果在重启后还要有文件节点,则要将加载命令写到启动脚本中去。
转载链接:http://blog.csdn.net/luckywang1103/article/details/16901625
补充:
VGA EDID 读取的驱动
-
#include <linux/module.h>
-
#include <linux/kernel.h>
-
#include <linux/device.h>
-
#include <linux/platform_device.h>
-
#include <linux/input.h>
-
#include <linux/interrupt.h>
-
#include <linux/irq.h>
-
#include <linux/fb.h>
-
#include <linux/init.h>
-
#include <linux/list.h>
-
#include <linux/delay.h>
-
#include <linux/dma-mapping.h>
-
#include <linux/err.h>
-
#include <linux/clk.h>
-
//#include <mach/clock.h>
-
#include <linux/uaccess.h>
-
#include <linux/cpufreq.h>
-
#include <linux/firmware.h>
-
#include <linux/kthread.h>
-
#include <linux/regulator/driver.h>
-
#include <linux/fsl_devices.h>
-
#include <linux/ipu.h>
-
-
#include <linux/console.h>
-
#include <linux/types.h>
-
-
#include <video/mxc_edid.h>
-
//#include "mxc/mxc_dispdrv.h"
-
-
#include <linux/mfd/mxc-hdmi-core.h>
-
//#include <mach/mxc_hdmi.h>
-
//#include <mach/hardware.h>
-
#include <asm/gpio.h>
-
#include <linux/gpio.h>
-
#include <linux/i2c.h>
-
#include <linux/i2c-dev.h>
-
-
#define edid_buf_size 256
-
-
struct i2c_client *edid_vga_client;
-
struct device *edid_vga_dev;
-
static struct class *edid_vga_class;
-
unsigned char *edid_all_buf;
-
unsigned int InOrOut;
-
-
-
static const struct of_device_id imx_vga_i2c_match[] = {
-
{ .compatible = "fsl,imx6-vga-i2c", },
-
{ /* sentinel */ }
-
};
-
-
static const struct i2c_device_id mxc_vga_i2c_id[] = {
-
{ "mxc_vga_i2c", 0 },
-
{},
-
};
-
MODULE_DEVICE_TABLE(i2c, mxc_vga_i2c_id);
-
-
-
static int edid_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num){
-
int ret = 0;
-
-
ret = i2c_transfer(adap, msgs, num);
-
-
-
if (ret != num)
-
{
-
printk(KERN_ERR"edid_i2c_transfer error %d\n",ret);
-
InOrOut = false;
-
return -EIO;
-
}
-
-
InOrOut = true;
-
return ret;
-
}
-
-
static int mxc_vga_edid_read(struct i2c_client *client){
-
int ret = 0;
-
unsigned char offset = 0;
-
struct i2c_adapter *adp = client->adapter;
-
-
struct i2c_msg msg[2] = {
-
{
-
.addr = client->addr,
-
.flags = 0,
-
.len = 1,
-
.buf = &offset,
-
}, {
-
.addr = client->addr,
-
.flags = I2C_M_RD,
-
.len = edid_buf_size,
-
.buf = edid_all_buf,
-
},
-
};
-
-
ret = edid_i2c_transfer(adp, msg, ARRAY_SIZE(msg));
-
return ret;
-
}
-
-
static ssize_t mxc_edid_show_state(struct device *dev, struct device_attribute *attr, char *buf)
-
{
-
int ret;
-
int len = 0;
-
-
ret = mxc_vga_edid_read(edid_vga_client);
-
if (ret <= 0){
-
printk("mxc_vga_edid_read error %d\n",ret);
-
return ret;
-
}
-
-
#if 0
-
for (j = 0; j < edid_buf_size/16; j++) {
-
for (i = 0; i < 16; i++)
-
len += sprintf(buf+len, "0x%02X ",
-
edid_all_buf[j*16 + i]);
-
len += sprintf(buf+len, "\n");
-
}
-
#else
-
memcpy(buf, edid_all_buf, edid_buf_size);
-
len = edid_buf_size;
-
#endif
-
-
return len;
-
}
-
-
-
static ssize_t mxc_rgb_show_state(struct device *dev,
-
struct device_attribute *attr, char *buf)
-
{
-
if(InOrOut == false)
-
strcpy(buf, "plugout\n");
-
else
-
strcpy(buf, "plugin\n");
-
-
return strlen(buf);
-
}
-
-
static DEVICE_ATTR(plugin_state, S_IRUGO, mxc_rgb_show_state, NULL);
-
static DEVICE_ATTR(show_edid, S_IRUGO, mxc_edid_show_state, NULL);
-
-
-
-
static int mxc_vga_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id){
-
-
int ret;
-
edid_vga_client = client;
-
InOrOut = false;
-
-
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE | I2C_FUNC_I2C))
-
return -ENODEV;
-
-
edid_all_buf = kmalloc(edid_buf_size, GFP_KERNEL);
-
if(edid_all_buf == NULL)
-
goto kmalloc_fail;
-
-
edid_vga_class = class_create(THIS_MODULE, "mxc_edid_class");
-
if(edid_vga_class == NULL)
-
goto class_create_fail;
-
-
edid_vga_dev = device_create(edid_vga_class, NULL, MKDEV(I2C_MAJOR, 50), NULL, "mxc_vga_edid");
-
if(edid_vga_dev == NULL)
-
goto device_create_fail;
-
-
ret = device_create_file(edid_vga_dev, &dev_attr_plugin_state);
-
if (ret < 0){
-
dev_warn(&client->dev, "cound not create sys node for dev_attr_plug_state\n");
-
goto device_create_file_fail;
-
}
-
ret = device_create_file(edid_vga_dev, &dev_attr_show_edid);
-
if (ret < 0){
-
dev_warn(&client->dev, "cound not create sys node for dev_attr_edid\n");
-
goto device_create_file_fail;
-
}
-
printk("mxc_vga_i2c_probe ok \n");
-
return 0;
-
-
device_create_file_fail:
-
device_destroy(edid_vga_class,MKDEV(I2C_MAJOR, 50));
-
device_create_fail:
-
class_destroy(edid_vga_class);
-
class_create_fail:
-
kfree(edid_all_buf);
-
kmalloc_fail:
-
printk("mxc_vga_i2c_probe error..\n");
-
return -1;
-
-
}
-
-
static int mxc_vga_i2c_remove(struct i2c_client *client)
-
{
-
device_destroy(edid_vga_class,MKDEV(I2C_MAJOR, 50));
-
class_destroy(edid_vga_class);
-
kfree(edid_all_buf);
-
-
printk("mxc_vga_i2c_remove_exit finished..\n");
-
return 0;
-
}
-
-
static struct i2c_driver mxc_vga_i2c_driver = {
-
.driver = {
-
.name = "mxc_vga_i2c",
-
.owner = THIS_MODULE,
-
.of_match_table = imx_vga_i2c_match,
-
},
-
.probe = mxc_vga_i2c_probe,
-
.remove = mxc_vga_i2c_remove,
-
.id_table = mxc_vga_i2c_id,
-
};
-
-
static int __init mxc_vga_i2c_init(void)
-
{
-
return i2c_add_driver(&mxc_vga_i2c_driver);
-
}
-
-
static void __exit mxc_vga_i2c_exit(void)
-
{
-
i2c_del_driver(&mxc_vga_i2c_driver);
-
}
-
-
module_init(mxc_vga_i2c_init);
-
module_exit(mxc_vga_i2c_exit);
阅读(4536) | 评论(0) | 转发(0) |