I2C自编设备驱动设计
来源:互联网 发布:mac网络恢复 最新 编辑:程序博客网 时间:2024/06/05 08:35
一、自编设备驱动模型
at24.c:
at24_driver:
at24_probe:
at24_bin_write:
at24_write:
at24_eeprom_write:
i2c_transfer:
然后看一下i2c_bin_read:
at24_read:
at24_eeprom_read:
二、对驱动程序的修改和移植
I2C设备的注册:
增加设备:
然后在tq2440_machine_init中添加:然后添加头文件:
然后会在开发板/sys/bus/i2c/devices/有一个0-0050的目录,有一个eeprom文件。
编写i2c-app.c文件:
at24.c:
- static int __init at24_init(void)
- {
- io_limit = rounddown_pow_of_two(io_limit);
- return i2c_add_driver(&at24_driver); //注册i2c驱动设备
- }
- static struct i2c_driver at24_driver = {
- .driver = {
- .name = "at24",
- .owner = THIS_MODULE,
- },
- .probe = at24_probe, //找到驱动对应的设备调用的函数
- .remove = __devexit_p(at24_remove),
- .id_table = at24_ids, //这个表里的设备都支持
- };
- static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
- {
- struct at24_platform_data chip;
- bool writable;
- bool use_smbus = false;
- struct at24_data *at24;
- int err;
- unsigned i, num_addresses;
- kernel_ulong_t magic;
- if (client->dev.platform_data) {
- chip = *(struct at24_platform_data *)client->dev.platform_data;
- } else {
- if (!id->driver_data) {
- err = -ENODEV;
- goto err_out;
- }
- magic = id->driver_data;
- chip.byte_len = BIT(magic & AT24_BITMASK(AT24_SIZE_BYTELEN));
- magic >>= AT24_SIZE_BYTELEN;
- chip.flags = magic & AT24_BITMASK(AT24_SIZE_FLAGS);
- /*
- * This is slow, but we can't know all eeproms, so we better
- * play safe. Specifying custom eeprom-types via platform_data
- * is recommended anyhow.
- */
- chip.page_size = 1;
- chip.setup = NULL;
- chip.context = NULL;
- }
- if (!is_power_of_2(chip.byte_len))
- dev_warn(&client->dev,
- "byte_len looks suspicious (no power of 2)!\n");
- if (!is_power_of_2(chip.page_size))
- dev_warn(&client->dev,
- "page_size looks suspicious (no power of 2)!\n");
- /* Use I2C operations unless we're stuck with SMBus extensions. */
- if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
- if (chip.flags & AT24_FLAG_ADDR16) {
- err = -EPFNOSUPPORT;
- goto err_out;
- }
- if (!i2c_check_functionality(client->adapter,
- I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
- err = -EPFNOSUPPORT;
- goto err_out;
- }
- use_smbus = true;
- }
- if (chip.flags & AT24_FLAG_TAKE8ADDR)
- num_addresses = 8;
- else
- num_addresses = DIV_ROUND_UP(chip.byte_len,
- (chip.flags & AT24_FLAG_ADDR16) ? 65536 : 256);
- at24 = kzalloc(sizeof(struct at24_data) +
- num_addresses * sizeof(struct i2c_client *), GFP_KERNEL);
- if (!at24) {
- err = -ENOMEM;
- goto err_out;
- }
- mutex_init(&at24->lock);
- at24->use_smbus = use_smbus;
- at24->chip = chip;
- at24->num_addresses = num_addresses;
- /*
- * Export the EEPROM bytes through sysfs, since that's convenient.
- * By default, only root should see the data (maybe passwords etc)
- */
- at24->bin.attr.name = "eeprom";
- at24->bin.attr.mode = chip.flags & AT24_FLAG_IRUGO ? S_IRUGO : S_IRUSR;
- at24->bin.read = at24_bin_read;
- at24->bin.size = chip.byte_len;
- at24->macc.read = at24_macc_read;
- writable = !(chip.flags & AT24_FLAG_READONLY);
- if (writable) {
- if (!use_smbus || i2c_check_functionality(client->adapter,
- I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) {
- unsigned write_max = chip.page_size;
- at24->macc.write = at24_macc_write;
- at24->bin.write = at24_bin_write; //这里注册了at24_bin_write,用户的write函数的调用接口
- at24->bin.attr.mode |= S_IWUSR;
- if (write_max > io_limit)
- write_max = io_limit;
- if (use_smbus && write_max > I2C_SMBUS_BLOCK_MAX)
- write_max = I2C_SMBUS_BLOCK_MAX;
- at24->write_max = write_max;
- /* buffer (data + address at the beginning) */
- at24->writebuf = kmalloc(write_max + 2, GFP_KERNEL);
- if (!at24->writebuf) {
- err = -ENOMEM;
- goto err_struct;
- }
- } else {
- dev_warn(&client->dev,
- "cannot write due to controller restrictions.");
- }
- }
- at24->client[0] = client;
- /* use dummy devices for multiple-address chips */
- for (i = 1; i < num_addresses; i++) {
- at24->client[i] = i2c_new_dummy(client->adapter,
- client->addr + i);
- if (!at24->client[i]) {
- dev_err(&client->dev, "address 0x%02x unavailable\n",
- client->addr + i);
- err = -EADDRINUSE;
- goto err_clients;
- }
- }
- err = sysfs_create_bin_file(&client->dev.kobj, &at24->bin); //创建一个文件应用程序实际上是在/sys目录下的文件,而这个文件就是它函数创建的。
- if (err)
- goto err_clients;
- i2c_set_clientdata(client, at24);
- dev_info(&client->dev, "%zu byte %s EEPROM %s\n",
- at24->bin.size, client->name,
- writable ? "(writable)" : "(read-only)");
- dev_dbg(&client->dev,
- "page_size %d, num_addresses %d, write_max %d%s\n",
- chip.page_size, num_addresses,
- at24->write_max,
- use_smbus ? ", use_smbus" : "");
- /* export data to kernel code */
- if (chip.setup)
- chip.setup(&at24->macc, chip.context);
- return 0;
- err_clients:
- for (i = 1; i < num_addresses; i++)
- if (at24->client[i])
- i2c_unregister_device(at24->client[i]);
- kfree(at24->writebuf);
- err_struct:
- kfree(at24);
- err_out:
- dev_dbg(&client->dev, "probe error %d\n", err);
- return err;
- }
- static ssize_t at24_bin_write(struct kobject *kobj, struct bin_attribute *attr,
- char *buf, loff_t off, size_t count)
- {
- struct at24_data *at24;
- at24 = dev_get_drvdata(container_of(kobj, struct device, kobj));
- return at24_write(at24, buf, off, count); //调用at24_write
- }
- static ssize_t at24_write(struct at24_data *at24, const char *buf, loff_t off,
- size_t count)
- {
- ssize_t retval = 0;
- if (unlikely(!count))
- return count;
- mutex_lock(&at24->lock);
- while (count) {
- ssize_t status;
- status = at24_eeprom_write(at24, buf, off, count); //调用at24_eeprom_write
- if (status <= 0) {
- if (retval == 0)
- retval = status;
- break;
- }
- buf += status;
- off += status;
- count -= status;
- retval += status;
- }
- mutex_unlock(&at24->lock);
- return retval;
- }
- 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 */ //I2C的消息
- 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控制器完成
- 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;
- }
- int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
- {
- int ret;
- if (adap->algo->master_xfer) {
- #ifdef DEBUG
- for (ret = 0; ret < num; ret++) {
- dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, "
- "len=%d%s\n", ret, (msgs[ret].flags & I2C_M_RD)
- ? 'R' : 'W', msgs[ret].addr, msgs[ret].len,
- (msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : "");
- }
- #endif
- if (in_atomic() || irqs_disabled()) {
- ret = mutex_trylock(&adap->bus_lock);
- if (!ret)
- /* I2C activity is ongoing. */
- return -EAGAIN;
- } else {
- mutex_lock_nested(&adap->bus_lock, adap->level);
- }
- ret = adap->algo->master_xfer(adap,msgs,num); //调用控制器中的算法
- mutex_unlock(&adap->bus_lock);
- return ret;
- } else {
- dev_dbg(&adap->dev, "I2C level transfers not supported\n");
- return -EOPNOTSUPP;
- }
- }
- static ssize_t at24_bin_read(struct kobject *kobj, struct bin_attribute *attr,
- char *buf, loff_t off, size_t count)
- {
- struct at24_data *at24;
- at24 = dev_get_drvdata(container_of(kobj, struct device, kobj));
- return at24_read(at24, buf, off, count); //调用at24_read
- }
- static ssize_t at24_read(struct at24_data *at24,
- char *buf, loff_t off, size_t count)
- {
- ssize_t retval = 0;
- if (unlikely(!count))
- return count;
- mutex_lock(&at24->lock);
- while (count) {
- ssize_t status;
- status = at24_eeprom_read(at24, buf, off, count); //继续调用at24_eeprom_read
- if (status <= 0) {
- if (retval == 0)
- retval = status;
- break;
- }
- buf += status;
- off += status;
- count -= status;
- retval += status;
- }
- mutex_unlock(&at24->lock);
- return retval;
- }
- static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf,
- unsigned offset, size_t count)
- {
- struct i2c_msg msg[2];
- u8 msgbuf[2];
- struct i2c_client *client;
- int status, i;
- memset(msg, 0, sizeof(msg));
- client = at24_translate_offset(at24, &offset);
- if (count > io_limit)
- count = io_limit;
- /* Smaller eeproms can work given some SMBus extension calls */
- if (at24->use_smbus) {
- if (count > I2C_SMBUS_BLOCK_MAX)
- count = I2C_SMBUS_BLOCK_MAX;
- status = i2c_smbus_read_i2c_block_data(client, offset,
- count, buf);
- dev_dbg(&client->dev, "smbus read %zu@%d --> %d\n",
- count, offset, status);
- return (status < 0) ? -EIO : status;
- }
- i = 0;
- if (at24->chip.flags & AT24_FLAG_ADDR16)
- msgbuf[i++] = offset >> 8;
- msgbuf[i++] = offset; //设置偏移
- msg[0].addr = client->addr; //第一条消息,提供从设备地址
- msg[0].buf = msgbuf;
- msg[0].len = i;
- msg[1].addr = client->addr; //第二条消息
- msg[1].flags = I2C_M_RD; //flags是读
- msg[1].buf = buf; //提供数据量
- msg[1].len = count;
- status = i2c_transfer(client->adapter, msg, 2);
- dev_dbg(&client->dev, "i2c read %zu@%d --> %d\n",
- count, offset, status);
- if (status == 2)
- return count;
- else if (status >= 0)
- return -EIO;
- else
- return status;
- }
二、对驱动程序的修改和移植
I2C设备的注册:
- static void __init tq2440_machine_init(void)
- {
- s3c24xx_fb_set_platdata(&tq2440_fb_info);
- s3c_i2c0_set_platdata(NULL);
- platform_add_devices(tq2440_devices, ARRAY_SIZE(tq2440_devices));
- EmbedSky_machine_init();
- s3c2410_gpio_setpin(S3C2410_GPG12, 0);
- s3c2410_gpio_cfgpin(S3C2410_GPG12, S3C2410_GPIO_OUTPUT);
- s3c24xx_udc_set_platdata(&EmbedSky_udc_cfg);
- }
- static struct at24_platform_data at24c02 = {
- .byte_len = 2048 / 8,
- .page_size = 8,
- .flags = 0,
- };
- static struct i2c_board_info __initdata tq2440_i2c_devices[] = {
- {
- I2C_BOARD_INFO("24c02", 0x50),
- .platform_data = &at24c02,
- },
- };
- i2c_register_board_info(0, tq2440_i2c_devices, ARRAY_SIZE(tq2440_i2c_devices));
- #include <linux/i2c.h>
- #include <linux/i2c/at24.h>
编写i2c-app.c文件:
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <unistd.h>
- int main()
- {
- char write_data[256],read_data[256];
- int fd;
- int i = 0;
- //打开at24c02对应的sys文件
- fd = open("/sys/bus/i2c/devices/0-0050/eeprom", O_RDWR);
- //写入数据
- for(i=0;i<256;i++)
- write_data[i] = i;
- lseek(fd, 0, SEEK_SET);
- write(fd, write_data, 256);
- //读出数据
- lseek(fd, 0, SEEK_SET);
- read(fd, read_data, 256);
- //打印对比
- for(i=0;i<256;i++)
- {
- if(i%16 == 0) printf("\r\n");
- printf("%3d ",read_data[i]);
- }
- printf("\n");
- close(fd);
- }
0
上一篇:I2C用户态驱动设计
下一篇:SPI总线介绍和裸机编程分析
相关热门文章
- SHTML是什么_SSI有什么用...
- 查看linux中某个端口(port)...
- 卡尔曼滤波的原理说明...
- shell中字符串操作
- 关于java中的“错误:找不到或...
给主人留下些什么吧!~~
评论热议
阅读全文
0 0
- I2C自编设备驱动设计
- Linux-IIC驱动(4)-自编IIC设备驱动程序
- I2C设备驱动流程
- I2C设备驱动流程
- i2c 具体设备驱动
- I2C设备驱动流程
- S5PV210 I2C设备驱动
- 移植i2c设备驱动
- linux i2c设备驱动
- Linux I2C 设备驱动
- S5PV210 I2C设备驱动
- linux i2c设备驱动 .
- I2C设备驱动编写
- I2C设备驱动流程
- linux I2C设备驱动
- I2C设备驱动详述
- Linux 设备驱动 - I2C
- linux i2c设备驱动
- MTD系统架构和yaffs2使用、Nandflash驱动设计
- I2C学习
- 蓝牙搜索
- I2C用户态驱动设计
- SpringBoot的热部署
- I2C自编设备驱动设计
- crontab执行shell脚本和直接运行的结果不一样
- SPI总线介绍和裸机编程分析
- SPI子系统
- Boa中关于StaticText的一个坑
- ros_indigo_arduino
- SPI驱动程序设计
- C++学习-拷贝构造函数
- linux常用进程及作业管理常用命令
原创粉丝点击
热门IT博客
热门问题
老师的惩罚
人脸识别
我在镇武司摸鱼那些年
重生之率土为王
我在大康的咸鱼生活
盘龙之生命进化
天生仙种
凡人之先天五行
春回大明朝
姑娘不必设防,我是瞎子
淘宝卡了
淘宝电子卡
中心淘宝卡
淘宝qq卡
建行淘宝卡
淘宝很卡
申请淘宝卡
办淘宝卡要多少钱
淘宝注册卡
我的淘宝卡
淘宝的流量卡
淘宝买流量卡
怎么申请淘宝卡
怎么使用淘宝卡
淘宝买的流量卡
淘宝上的流量卡
怎样用淘宝卡买东西
开淘宝很卡
电脑上淘宝卡
淘宝 选号
淘宝克
淘宝 手机淘宝
手机注册淘宝账号
免费注册淘宝账号
注册淘宝帐号
怎么查淘宝账号
注册淘宝账户
怎么样注册淘宝账号
怎样注册淘宝账号
怎么注册淘宝账号
淘宝账户注册
什么是淘宝账号
淘宝账户怎么注册
手机淘宝怎么注册账号
怎样申请淘宝账号
注册淘宝账号手机注册
淘宝账号怎么注册
淘宝账号出售
淘宝账号是哪个
怎么开通淘宝账号
出售淘宝账号