linux 之i2c 24FC256驅動

          基於zynq平臺調試 24FC256驅動。需要注意的是此款eeprom是32K x 8 (256 Kbit)。爲了支持此款eeprom的尋址範圍,地址需要16位來表示。

          1.先看此款eeprom的設備地址。

               

         a0,a1,a2,三根線可以選擇設備的地址爲多少。我們靠硬件把地址設置爲0x56(0b1010110)。

       2. 寫一byte操作。代碼如下:

		val[0] = 0; //high addr
		val[1] = 0; //low addr
		val[2] = 0xf; //往0地址寫f
		/* 數據傳輸三要素: 源,目的,長度 */
		msg_w.addr  = client->addr;  /* 目的 */
		msg_w.buf   = val;                   /* 源 */
		msg_w.len   = 3;                     /* 高地址+低地址+數據=3 bytes */
		msg_w.flags = 0;                     /* 表示寫 */
		ret =  i2c_transfer(client->adapter, &msg_w, 1);
		printk(KERN_ERR "write ret = %d \n\r",ret);

       用示波器抓SCL與sda。即往0地址寫入0xf。

 

和datasheet給的寫byte操作一致:

2.讀一byte,代碼如下

		/* 數據傳輸三要素: 源,目的,長度 */
		addr_read[0] = i; //high addr
		addr_read[1] = 0; //low addr
		/* 讀AT24CXX時,要先把要讀的存儲空間的地址發給它 */
		msg[0].addr  = client->addr;  /* 目的 */
		msg[0].buf	 = addr_read;			  /* 源 */
		msg[0].len	 = 2;					  /* 地址=2 byte */
		msg[0].flags = 0;					  /* 表示寫 */

		/* 然後啓動讀操作 */
		msg[1].addr  = client->addr;  /* 源 */
		msg[1].buf	 = &data;				  /* 目的 */
		msg[1].len	 = 1;					  /* 數據=1 byte */
		msg[1].flags = I2C_M_RD;
		ret = i2c_transfer(client->adapter, msg, 2);
		printk(KERN_ERR"ret = %d,data = 0x%x",ret,data);

讀操作原理如下:需要先寫地址,然後進行讀操作。也就是需要2步。

示波器抓的信號如下:

2.1.寫要讀取數據的地址:

2.2,開始讀一byte

讀寫驗證代碼:

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
#include <linux/mod_devicetable.h>
#include <linux/log2.h>
#include <linux/bitops.h>
#include <linux/jiffies.h>
#include <linux/of.h>
#include <linux/acpi.h>
#include <linux/i2c.h>
#include <linux/platform_data/at24.h>


static const struct i2c_device_id myat24_ids[] = {
	{ "24c256", 1 },
	{ /* END OF LIST */ }
};

static int myat24_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
	unsigned char addr_read[2] = {0};
	unsigned char data,i;
	struct i2c_msg msg[2];
	struct i2c_msg msg_w;
	char val[3] = {0};
	int ret = 0;
	memset(msg,0,sizeof(msg));
	printk(KERN_ERR "addr: 0x%x,name:%s \n\r",client->addr,client->name);

	#if 0
	for(i = 0; i < 10; i++) {
		val[0] = 0; //high addr
		val[1] = i; //low addr
		val[2] = i; //val
		/* 數據傳輸三要素: 源,目的,長度 */
		msg_w.addr  = client->addr;  /* 目的 */
		msg_w.buf   = val;                   /* 源 */
		msg_w.len   = 3;                     /* 高地址+低地址+數據=3 byte */
		msg_w.flags = 0;                     /* 表示寫 */
		ret =  i2c_transfer(client->adapter, &msg_w, 1);
		printk(KERN_ERR "write ret = %d \n\r",ret);
		//i2c_smbus_write_byte_data(client,addr,addr);
	}
	#endif
	for(i = 0; i < 10; i++) {
		/* 數據傳輸三要素: 源,目的,長度 */
		addr_read[0] = 0; //high addr
		addr_read[1] = i; //low addr
		/* 讀AT24CXX時,要先把要讀的存儲空間的地址發給它 */
		msg[0].addr  = client->addr;  /* 目的 */
		msg[0].buf	 = addr_read;			  /* 源 */
		msg[0].len	 = 2;					  /* 地址=2 byte */
		msg[0].flags = 0;					  /* 表示寫 */

		/* 然後啓動讀操作 */
		msg[1].addr  = client->addr;  /* 源 */
		msg[1].buf	 = &data;				  /* 目的 */
		msg[1].len	 = 1;					  /* 數據=1 byte */
		msg[1].flags = I2C_M_RD;
		ret = i2c_transfer(client->adapter, msg, 2);
		//data = i2c_smbus_read_byte_data(client, addr);
		printk(KERN_ERR"ret = %d,data = 0x%x",ret,data);
	}
	return 0;
}

static int myat24_remove(struct i2c_client *client)
{
	printk(KERN_ERR"remove myat24 \n\r");

	return 0;
}


static struct i2c_driver myat24_driver = {
	.driver = {
		.name = "at24",
	},
	.probe = myat24_probe,
	.remove = myat24_remove,
	.id_table = myat24_ids,
};

static int __init my_at24_init(void)
{
	return i2c_add_driver(&myat24_driver);
}
static void __exit my_at24_exit(void)
{
	i2c_del_driver(&myat24_driver);
}

module_init(my_at24_init);
module_exit(my_at24_exit);

MODULE_AUTHOR("liu");
MODULE_LICENSE("GPL");

dts:

&i2c0 {
    status = "okay";
    clock-frequency = <100000>;
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_i2c0_default>;
    at24@56 {
            compatible = "at24,24c256";
            pagesize = <64>;
            reg = <0x56>;
    };

};

後話:

爲了debug I2C方便,可以把如下信息打卡:

這樣代碼中的:debug信息就可以打印出來了,方便調試。

#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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章