mini2440 i2c设备支持

内核版本:linux-2.6.32.2  实验平台:mini2440

1. 添加主控设备支持
i2c主控制器也是一个设备,只是在内核被虚拟成了一个平台设备,平台设备在内核中已经被定义了,定义在plat-s3c/dev-i2c0.c中:
static struct resource s3c_i2c_resource[] = {
	[0] = {
		.start = S3C_PA_IIC,
		.end   = S3C_PA_IIC + SZ_4K - 1,
		.flags = IORESOURCE_MEM,
	},
	[1] = {
		.start = IRQ_IIC,
		.end   = IRQ_IIC,
		.flags = IORESOURCE_IRQ,
	},
};

struct platform_device s3c_device_i2c0 = {
	.name		  = "s3c2410-i2c",
#ifdef CONFIG_S3C_DEV_I2C1
	.id		  = 0,
#else
	.id		  = -1,
#endif
	.num_resources	  = ARRAY_SIZE(s3c_i2c_resource),
	.resource	  = s3c_i2c_resource,
};

那么我只需要将这个平台设备添加到mini2440_devices这个数组里面,最终这个平台设备将被注册到内核中。

2. 添加主控驱动支持
主控制器驱动为drivers/i2c/busses/i2c-s3c2410.c,那么我们只需要配置一下就可以了:

   Device Drivers  --->
	<*> I2C support  --->
		I2C Hardware Bus support  --->
			<*> S3C2410 I2C Driver

3. at24c08 i2c设备的注册
这里使用i2c_register_board_info()函数来注册i2c设备,首先是使用I2C_BOARD_INFO宏来定义i2c设备信息:
static struct at24_platform_data at24_platdata = {
	.byte_len = 8192,
	.page_size = 16,
};

static struct i2c_board_info mini2440_i2c_devices[] = {
	{
		I2C_BOARD_INFO("24c08", 0x50),
		.platform_data = &at24_platdata,
	}
};
mini2440上at24c08的i2c地址为0x50,并且是挂载到i2c0上的,在mini2440_machine_init去完成注册:
i2c_register_board_info(0, mini2440_i2c_devices, ARRAY_SIZE(mini2440_i2c_devices));
其中的第一个参数需要注意,为i2c的总线号。

最后还需要注意别忘了包含这两个头文件:
<linux/i2c.h>
<linux/i2c/at24.h>

4. at24c08驱动支持
驱动代码就用默认的drivers/misc/eeprom/at24.c,配置如下:
    Device Drivers  --->
	[*] Misc devices  ---> 
		EEPROM support  --->
			-*- I2C EEPROMs from most vendors

5. 验证
那么怎么去验证我们添加的i2c驱动和i2c设置是匹配成功的了呢,进入到这个目录下:/sys/bus/i2c/drivers/at24,然后可以看到一个文件0-0050,说明i2c驱动和i2c设备是匹配成功了的。

//2016.3.27 add
linux自带的eeprom驱动程序可能不便于测试,为此,我写了个简单的i2c驱动用来测试at24c08,代码如下:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/types.h>
#include <linux/uaccess.h>

MODULE_LICENSE("GPL");

struct at24_data {
	struct cdev cdev;
	struct i2c_client *client;
};

int at24_read_block(struct i2c_client *client,
		u8 addr, u8 len, u8 *values)
{
	return i2c_smbus_read_i2c_block_data(client, addr, len, values);
}

int at24_write_block(struct i2c_client *client,
		u8 addr, u8 len, u8 *values)
{
	return i2c_smbus_write_i2c_block_data(client, addr, len, values);
}

#define BLOCK_MAX 32

static size_t at24_read(struct file *file, char __user *buf,
			size_t count, loff_t *pos)
{
	struct at24_data *at24 = file->private_data;
	int num;
	u8 block[BLOCK_MAX];

	if (count > BLOCK_MAX)
		count = BLOCK_MAX;

	num = at24_read_block(at24->client, *pos, count, block);

	if (copy_to_user(buf, block, num)) {
		return -EFAULT;
	} else {
		*pos += num;
		return num;
	}
}

static size_t at24_write(struct file *file, char __user *buf,
			size_t count, loff_t *pos)
{
	struct at24_data *at24 = file->private_data;
	int num;
	u8 block[BLOCK_MAX];

	if (count > BLOCK_MAX)
		count = BLOCK_MAX;

	if (copy_from_user(block, buf, count)) {
		return -EFAULT;
	} else {
		num = at24_write_block(at24->client, *pos, count, block);

		*pos += num;
		return num;
	}
}

static size_t at24_open(struct inode *inode, struct file *file)
{
	struct at24_data *at24;

	at24 = container_of(inode->i_cdev, struct at24_data, cdev);
	file->private_data = at24;
	return 0;
}

static size_t at24_close(struct inode *inode, struct file *file)
{
	file->private_data = NULL;
	return 0;
}

static struct file_operations at24_fops = {
	.open		= at24_open,
	.release	= at24_close,
	.read		= at24_read,
	.write		= at24_write,
};

static int at24_probe(struct i2c_client *client,
		const struct i2c_device_id *id)
{
	struct at24_data *at24;
	int retval = 0;
	dev_t dev_id;

	at24 = kzalloc(sizeof(struct at24_data), GFP_KERNEL);
	if (!at24) {
		return -ENOMEM;
	}

	at24->client = client;

	retval = alloc_chrdev_region(&dev_id, 0, 1, "at24c08");
	if (retval < 0) {
		dev_err(&client->dev,
			"unable to allocate char device region\n");
		goto err_out;
	}

	cdev_init(&at24->cdev, &at24_fops);

	retval = cdev_add(&at24->cdev, dev_id, 1);
	if (retval < 0) {
		dev_err(&client->dev,
			"unable to register char device\n");
		goto err_free_region;
	}

	i2c_set_clientdata(client, at24);

	return 0;
err_free_region:
	unregister_chrdev_region(dev_id, 1);
err_out:
	kfree(at24);
	return -1;
}

static int at24_remove(struct i2c_client *client)
{
	struct at24_data *at24 = i2c_get_clientdata(client);

	cdev_del(&at24->cdev);
	kfree(at24);
	unregister_chrdev_region(at24->cdev.dev, 1);

	return 0;
}

static struct i2c_device_id at24_ids[] = {
	{ "at24c08", 0 },
	{ }
};
MODULE_DEVICE_TABLE(i2c, at24_ids);

static struct i2c_driver at24_driver = {
	.driver = {
		.name	= "at24c08",
	},
	.id_table	= at24_ids,
	.probe		= at24_probe,
	.remove		= at24_remove,
};

static int __init at24_init(void)
{
	return i2c_add_driver(&at24_driver);
}

static void __exit at24_exit(void)
{
	i2c_del_driver(&at24_driver);
}

module_init(at24_init);
module_exit(at24_exit);
编译好了之后,首先insmod,然后mknod,测试app程序如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

//#define TEST_WRITE	1
#define TEST_READ	1

int main(int argc, char *argv[])
{
	int fd;
	int i;
	char buf[8];

	if (argc < 2)
		exit(1);

	fd = open(argv[1], O_RDWR);
	if (fd < 0)
		exit(1);

#ifdef TEST_WRITE
	for (i = 0; i < sizeof(buf); i++)
		buf[i] = i;
	write(fd, buf, sizeof(buf));
#endif

#ifdef TEST_READ
	memset(buf, 0, sizeof(buf));

	read(fd, buf, sizeof(buf));
	for (i = 0; i < sizeof(buf); i++)
		printf("%d ", buf[i]);
	printf("\n");
#endif

	close(fd);
	exit(0);
}

最后测试得即使掉电之后也能正确读取到写入的数据,说明程序是ok的。

// 2016-05-15 add
另一个i2c read函数

int at24_read_array(struct i2c_client *client,
		u8 addr, u8 len, u8 *vals)
{
	struct i2c_msg msgs[] = {
		{
			.addr = client->addr,
			.flags = 0,
			.len = 1,
			.buf = &addr
		},
		{
			.addr = client->addr,
			.flags = I2C_M_RD,
			.len = len,
			.buf = vals
		}
	};
	int ret;

	ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
	if (ret < 0)
		printk("i2c_transfer error\n");

	return ret;
}
这里使用i2c_transfer来操作i2c,注意i2c_transfer的返回值,正确返回的是传输i2c_msg的个数。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值