1. 程式人生 > >Zynq-Linux移植學習筆記之31-使用者自定義I2C驅動

Zynq-Linux移植學習筆記之31-使用者自定義I2C驅動

1、背景介紹

板子上通過ZYNQ的I2C-0控制器連線了三片DBF晶片和一片Ti的226測功耗晶片,示意圖如下:

如上圖所示,三塊DBF晶片的I2C地址分別為2,4,8,Ti 226晶片的I2C地址為0x40.現在需要ZYNQ通過I2C匯流排讀寫這四塊晶片的暫存器數值。

2、I2C時序說明

之前除錯過cps1848 RapidIO交換晶片,想來既然都是i2c從裝置,知道了slave的地址操作過程應該差不多,不過真正除錯的時候才發現雖然這些裝置都遵循I2C協議,但在i2c的讀寫時序上還是存在不同,下面將cps1848與dbf的i2c讀寫時序進行對比,Ti 226的類似。

以上是從1848 datasheet中摘錄出的i2c讀寫時序圖,之前除錯時採用的是7位地址,即後面兩個圖。

從圖中可以得知,讀操作時i2c master先發slave地址(加start共8bit),再發要讀寫的空間地址(即暫存器offset,共24bit),這兩個部分組成第一個message.後一個message包括slave地址(8bit)和接收資料的緩衝區(32bit)。完成整個操作後表示讀結束。對應程式碼如下:

Msgbuf即對應offset,共24bit,msg即為上面提到的message,呼叫i2c_transfer()傳送兩個msg正好匹配1848的讀時序圖。

再來看寫操作,先是一個slave地址(8bit),再24bit偏移量,然後是待寫入的32bit共同組成一個message.程式碼如下:

從程式碼中可以看到,這裡把要寫入的資料和長度都放入msgbuf中,前面加上24bit offset,最後組裝為一個msg傳送出去。

搞清楚了i2c讀寫時序,針對不同晶片只需要根據datasheet時序關係進行程式碼修改即可,dbf晶片讀寫時序如下

DBF晶片也支援7地址和10地址操作,顯然這裡選擇7地址改動最小。和1848相比,這裡的讀操作是先8bit地址,然後8bit要讀的資料長度,再8bit offset。通常要讀的資料為32bit,所以NUM這裡設為固定值0x04,程式碼改動如下:

要調整的地方就是msgbuf大小變為16bit,內容調整,msg[0]的len也設為2.

寫操作也類似調整,程式碼如下:

Ti 226晶片也根據datasheet修改即可,這裡不加贅述。

3、核心配置

將DBF驅動程式碼和226驅動程式碼編譯進核心即可,這裡圖省事直接obj-y,dbf驅動名稱忘了改,沿用1848了。

程式碼分別如下

/*
 * CPS1848 bus driver
 *
 * Copyright (C) 2014 CGT Corp.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */

#define DEBUG

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <linux/delay.h>

#include <linux/serial_core.h>

/* Each client has this additional data */
#define USER_EEPROM_SIZE	0xFFFF48
#define USER_XFER_MAX_COUNT	0x8

/* Addresses to scan */
static const unsigned short cps1848_i2c[] = { 0x3, I2C_CLIENT_END };

static unsigned read_timeout = 25;
module_param(read_timeout, uint, 0);
MODULE_PARM_DESC(read_timeout, "Time (in ms) to try reads (default 25)");

static unsigned write_timeout = 25;
module_param(write_timeout, uint, 0);
MODULE_PARM_DESC(write_timeout, "Time (in ms) to try writes (default 25)");

struct cps1848_data {
	struct mutex	lock;
	u8	*data;
};

static ssize_t cps1848_eeprom_read( struct i2c_client *client,
	char *buf, unsigned offset, size_t count)
{
	struct i2c_msg msg[2];
	u8 msgbuf[4];
	unsigned long timeout, transfer_time;
	int status;

	memset(msg, 0, sizeof(msg));

	//msgbuf[0] = (u8)((offset >> 18) & 0x3f);
	//msgbuf[1] = (u8)((offset >> 10) & 0xff);
	//msgbuf[2] = (u8)((offset >>  2) & 0xff);

	msgbuf[0] = 0x04;
	msgbuf[1] = 0x00;

	msg[0].addr = client->addr;
	msg[0].buf = msgbuf;
	msg[0].len = 2;

	msg[1].addr = client->addr;
	msg[1].flags = I2C_M_RD;
	msg[1].buf = buf;
	msg[1].len = count;

	/*
	 * Reads fail if the previous write 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(read_timeout);
	do {
		transfer_time = jiffies;

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

		if (status == 2)
			status = count;

		dev_dbg(&client->dev, "read %[email protected]%lx --> %d (%ld)\n",
				count, (unsigned long)offset, status, jiffies);

		if (status == count)
			return count;

		/* REVISIT: at HZ=100, this is sloooow */
		msleep(1);
	} while (time_before(transfer_time, timeout));

	return -ETIMEDOUT;

 }


static ssize_t cps1848_read(struct file *filp, struct kobject *kobj,
			    struct bin_attribute *bin_attr,
			    char *buf, loff_t offset, size_t count)
{
	struct i2c_client *client = kobj_to_i2c_client(kobj);
	struct cps1848_data *data = i2c_get_clientdata(client);

	ssize_t retval = 0;

	if (offset > USER_EEPROM_SIZE)
		return 0;

	if (offset + count > USER_EEPROM_SIZE)
		count = USER_EEPROM_SIZE - offset;

	mutex_lock(&data->lock);

	dev_dbg(&client->dev, "cps1848 start read %[email protected]%lx ..\n", count, (unsigned long)offset);

	while (count > 0) {
		ssize_t	status = count>USER_XFER_MAX_COUNT?USER_XFER_MAX_COUNT:count;
		status = cps1848_eeprom_read(client, buf, offset, status);
		if (status <= 0) {
			if (retval == 0)
				retval = status;
			break;
		}
		buf += status;
		offset += status;
		count -= status;
		retval += status;
	}

	dev_dbg(&client->dev, "cps1848 end read %[email protected]%lx  !\n", retval, (unsigned long)offset);

	mutex_unlock(&data->lock);

	return retval;

 }

static ssize_t cps1848_eeprom_write(
	struct i2c_client *client,
	struct cps1848_data *data,
	char *buf, unsigned offset, size_t count)
{
	struct i2c_msg msg[1];
	u8 *msgbuf;
	unsigned long timeout, transfer_time;
	int status;

	memset(msg, 0, sizeof(msg));

	msgbuf = data->data;

//	msgbuf[0] = (u8)((offset >> 18) & 0x3f);
//	msgbuf[1] = (u8)((offset >> 10) & 0xff);
//	msgbuf[2] = (u8)((offset >>  2) & 0xff);

	msgbuf[0] = 0x04;
	msgbuf[1] = 0x00;

	memcpy(msgbuf+2, buf, count);

	msg[0].addr = client->addr;
	msg[0].buf = msgbuf;
	msg[0].len = 2 + count;

	/*
	 * Reads fail if the previous write 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 {
		transfer_time = jiffies;

		status = i2c_transfer(client->adapter, msg, 1);

		if (status == 1)
			status = count;

		dev_dbg(&client->dev, "write %[email protected]%lx --> %d (%ld)\n",
				count, (unsigned long)offset, status, jiffies);

		if (status == count)
			return count;

		/* REVISIT: at HZ=100, this is sloooow */
		msleep(1);
	} while (time_before(transfer_time, timeout));

	return -ETIMEDOUT;
 }

static ssize_t cps1848_write(struct file *filp, struct kobject *kobj,
			    struct bin_attribute *bin_attr,
			    char *buf, loff_t offset, size_t count)
{
	struct i2c_client *client = kobj_to_i2c_client(kobj);
	struct cps1848_data *data = i2c_get_clientdata(client);

	ssize_t retval = 0;

	if (offset > USER_EEPROM_SIZE)
		return 0;

	if (offset + count > USER_EEPROM_SIZE)
		count = USER_EEPROM_SIZE - offset;

	mutex_lock(&data->lock);

	dev_dbg(&client->dev, "cps1848 start write %[email protected]%lx ..\n", count, (unsigned long)offset);

	while (count > 0) {
		ssize_t	status = count>USER_XFER_MAX_COUNT?USER_XFER_MAX_COUNT:count;
		status = cps1848_eeprom_write(client, data, buf, offset, status);
		if (status <= 0) {
			if (retval == 0)
				retval = status;
			break;
		}
		buf += status;
		offset += status;
		count -= status;
		retval += status;
	}

	dev_dbg(&client->dev, "cps1848 end write %[email protected]%lx  !\n", retval, (unsigned long)offset);

	mutex_unlock(&data->lock);

	return retval;

 }

static struct bin_attribute user_eeprom_attr = {
	.attr = {
		.name = "eeprom",
		.mode = (S_IRUSR | S_IWUSR),
	},
	.size = USER_EEPROM_SIZE,
	.read = cps1848_read,
	.write = cps1848_write,
};

/* Return 0 if detection is successful, -ENODEV otherwise */
static int cps1848_detect(struct i2c_client *client, struct i2c_board_info *info)
{
	struct i2c_adapter *adapter = client->adapter;

	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
		dev_dbg(&client->dev, "cps1848 detect error for BYTE access !\n");
		return -ENODEV;
	}

	strlcpy(info->type, "eeprom", I2C_NAME_SIZE);

	return 0;
 }

static int cps1848_probe(struct i2c_client *client,
			 const struct i2c_device_id *id)
{
	struct i2c_adapter *adapter = client->adapter;
	struct cps1848_data *data;
	int err ;

	dev_notice(&client->dev, "CPS1848 driver\n" );

	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
		dev_err(&client->dev, "CPS1848 driver:  BYTE DATA not supported! \n" );
		return -ENODEV;
	}

	if (!(data = kzalloc(sizeof(struct cps1848_data), GFP_KERNEL))) {
		dev_err(&client->dev, "CPS1848 driver:  Memory alloc error ! \n" );
		return -ENOMEM;
	}

	/* alloc buffer */
	data->data = devm_kzalloc(&client->dev, USER_XFER_MAX_COUNT + 8, GFP_KERNEL);
	if (!data->data) {
		dev_err(&client->dev, "CPS1848 driver:  Memory alloc error ! \n" );
		err = -ENOMEM;
		goto exit_kfree;
	}

	/* Init real i2c_client */
	i2c_set_clientdata(client, data);
	mutex_init(&data->lock);

	err = sysfs_create_bin_file(&client->dev.kobj, &user_eeprom_attr);
	if (err) {
		dev_err(&client->dev, "CPS1848 driver:  sysfs create error ! \n" );
		goto exit_kfree;
	}

	return 0;

exit_kfree:
	if(data->data)
		kfree(data->data);
	kfree(data);
	return err;
 }

static int cps1848_remove(struct i2c_client *client)
{
	struct cps1848_data *data = i2c_get_clientdata(client);

	sysfs_remove_bin_file(&client->dev.kobj, &user_eeprom_attr);
	if(data->data)
		kfree(data->data);
	kfree(data);

	return 0;
 }

static const struct i2c_device_id cps1848_id[] = {
	{ "cps1848", 0 },
	{ }
};
MODULE_DEVICE_TABLE(i2c, cps1848_id);

static struct i2c_driver cps1848_driver = {
	.driver = {
		.name	= "cps1848",
	},
	.probe		= cps1848_probe,
	.remove		= cps1848_remove,
	.id_table	= cps1848_id,

	.class		= I2C_CLASS_SPD,
	.detect		= cps1848_detect,
	.address_list	= cps1848_i2c,
};

module_i2c_driver(cps1848_driver);

MODULE_AUTHOR("RobinLee");
MODULE_DESCRIPTION("CPS1848 driver");
MODULE_LICENSE("GPL");
/*
 * cps226 bus driver
 *
 * Copyright (C) 2014 CGT Corp.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */

#define DEBUG

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <linux/delay.h>

#include <linux/serial_core.h>

/* Each client has this additional data */
#define USER_EEPROM_SIZE	0xFFFF48
#define USER_XFER_MAX_COUNT	0x8

/* Addresses to scan */
static const unsigned short cps226_i2c[] = { 0x3, I2C_CLIENT_END };

static unsigned read_timeout = 25;
module_param(read_timeout, uint, 0);
MODULE_PARM_DESC(read_timeout, "Time (in ms) to try reads (default 25)");

static unsigned write_timeout = 25;
module_param(write_timeout, uint, 0);
MODULE_PARM_DESC(write_timeout, "Time (in ms) to try writes (default 25)");

struct cps226_data {
	struct mutex	lock;
	u8	*data;
};

static ssize_t cps226_eeprom_read( struct i2c_client *client,
	char *buf, unsigned offset, size_t count)
{
	struct i2c_msg msg[2];
	u8 msgbuf[4];
	unsigned long timeout, transfer_time;
	int status;

	memset(msg, 0, sizeof(msg));

	msgbuf[0] = (u8)(offset & 0xff);


	msg[0].addr = client->addr;
	msg[0].buf = msgbuf;
	msg[0].len = 1;

	msg[1].addr = client->addr;
	msg[1].flags = I2C_M_RD;
	msg[1].buf = buf;
	msg[1].len = count;

	/*
	 * Reads fail if the previous write 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(read_timeout);
	do {
		transfer_time = jiffies;

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

		if (status == 2)
			status = count;

		dev_dbg(&client->dev, "read %[email protected]%lx --> %d (%ld)\n",
				count, (unsigned long)offset, status, jiffies);

		if (status == count)
			return count;

		/* REVISIT: at HZ=100, this is sloooow */
		msleep(1);
	} while (time_before(transfer_time, timeout));

	return -ETIMEDOUT;

 }


static ssize_t cps226_read(struct file *filp, struct kobject *kobj,
			    struct bin_attribute *bin_attr,
			    char *buf, loff_t offset, size_t count)
{
	struct i2c_client *client = kobj_to_i2c_client(kobj);
	struct cps226_data *data = i2c_get_clientdata(client);

	ssize_t retval = 0;

	if (offset > USER_EEPROM_SIZE)
		return 0;

	if (offset + count > USER_EEPROM_SIZE)
		count = USER_EEPROM_SIZE - offset;

	mutex_lock(&data->lock);

	dev_dbg(&client->dev, "cps226 start read %[email protected]%lx ..\n", count, (unsigned long)offset);

	while (count > 0) {
		ssize_t	status = count>USER_XFER_MAX_COUNT?USER_XFER_MAX_COUNT:count;
		status = cps226_eeprom_read(client, buf, offset, status);
		if (status <= 0) {
			if (retval == 0)
				retval = status;
			break;
		}
		buf += status;
		offset += status;
		count -= status;
		retval += status;
	}

	dev_dbg(&client->dev, "cps226 end read %[email protected]%lx  !\n", retval, (unsigned long)offset);

	mutex_unlock(&data->lock);

	return retval;

 }

static ssize_t cps226_eeprom_write(
	struct i2c_client *client,
	struct cps226_data *data,
	char *buf, unsigned offset, size_t count)
{
	struct i2c_msg msg[1];
	u8 *msgbuf;
	unsigned long timeout, transfer_time;
	int status;

	memset(msg, 0, sizeof(msg));

	msgbuf = data->data;

//	msgbuf[0] = (u8)((offset >> 18) & 0x3f);
//	msgbuf[1] = (u8)((offset >> 10) & 0xff);
//	msgbuf[2] = (u8)((offset >>  2) & 0xff);

	msgbuf[0] = (u8)(offset & 0xff);

	memcpy(msgbuf+1, buf, count);

	msg[0].addr = client->addr;
	msg[0].buf = msgbuf;
	msg[0].len = 1 + count;

	/*
	 * Reads fail if the previous write 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 {
		transfer_time = jiffies;

		status = i2c_transfer(client->adapter, msg, 1);

		if (status == 1)
			status = count;

		dev_dbg(&client->dev, "write %[email protected]%lx --> %d (%ld)\n",
				count, (unsigned long)offset, status, jiffies);

		if (status == count)
			return count;

		/* REVISIT: at HZ=100, this is sloooow */
		msleep(1);
	} while (time_before(transfer_time, timeout));

	return -ETIMEDOUT;
 }

static ssize_t cps226_write(struct file *filp, struct kobject *kobj,
			    struct bin_attribute *bin_attr,
			    char *buf, loff_t offset, size_t count)
{
	struct i2c_client *client = kobj_to_i2c_client(kobj);
	struct cps226_data *data = i2c_get_clientdata(client);

	ssize_t retval = 0;

	if (offset > USER_EEPROM_SIZE)
		return 0;

	if (offset + count > USER_EEPROM_SIZE)
		count = USER_EEPROM_SIZE - offset;

	mutex_lock(&data->lock);

	dev_dbg(&client->dev, "cps226 start write %[email protected]%lx ..\n", count, (unsigned long)offset);

	while (count > 0) {
		ssize_t	status = count>USER_XFER_MAX_COUNT?USER_XFER_MAX_COUNT:count;
		status = cps226_eeprom_write(client, data, buf, offset, status);
		if (status <= 0) {
			if (retval == 0)
				retval = status;
			break;
		}
		buf += status;
		offset += status;
		count -= status;
		retval += status;
	}

	dev_dbg(&client->dev, "cps226 end write %[email protected]%lx  !\n", retval, (unsigned long)offset);

	mutex_unlock(&data->lock);

	return retval;

 }

static struct bin_attribute user_eeprom_attr = {
	.attr = {
		.name = "eeprom",
		.mode = (S_IRUSR | S_IWUSR),
	},
	.size = USER_EEPROM_SIZE,
	.read = cps226_read,
	.write = cps226_write,
};

/* Return 0 if detection is successful, -ENODEV otherwise */
static int cps226_detect(struct i2c_client *client, struct i2c_board_info *info)
{
	struct i2c_adapter *adapter = client->adapter;

	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
		dev_dbg(&client->dev, "cps226 detect error for BYTE access !\n");
		return -ENODEV;
	}

	strlcpy(info->type, "eeprom", I2C_NAME_SIZE);

	return 0;
 }

static int cps226_probe(struct i2c_client *client,
			 const struct i2c_device_id *id)
{
	struct i2c_adapter *adapter = client->adapter;
	struct cps226_data *data;
	int err ;

	dev_notice(&client->dev, "cps226 driver\n" );

	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
		dev_err(&client->dev, "cps226 driver:  BYTE DATA not supported! \n" );
		return -ENODEV;
	}

	if (!(data = kzalloc(sizeof(struct cps226_data), GFP_KERNEL))) {
		dev_err(&client->dev, "cps226 driver:  Memory alloc error ! \n" );
		return -ENOMEM;
	}

	/* alloc buffer */
	data->data = devm_kzalloc(&client->dev, USER_XFER_MAX_COUNT + 8, GFP_KERNEL);
	if (!data->data) {
		dev_err(&client->dev, "cps226 driver:  Memory alloc error ! \n" );
		err = -ENOMEM;
		goto exit_kfree;
	}

	/* Init real i2c_client */
	i2c_set_clientdata(client, data);
	mutex_init(&data->lock);

	err = sysfs_create_bin_file(&client->dev.kobj, &user_eeprom_attr);
	if (err) {
		dev_err(&client->dev, "cps226 driver:  sysfs create error ! \n" );
		goto exit_kfree;
	}

	return 0;

exit_kfree:
	if(data->data)
		kfree(data->data);
	kfree(data);
	return err;
 }

static int cps226_remove(struct i2c_client *client)
{
	struct cps226_data *data = i2c_get_clientdata(client);

	sysfs_remove_bin_file(&client->dev.kobj, &user_eeprom_attr);
	if(data->data)
		kfree(data->data);
	kfree(data);

	return 0;
 }

static const struct i2c_device_id cps226_id[] = {
	{ "cps226", 0 },
	{ }
};
MODULE_DEVICE_TABLE(i2c, cps226_id);

static struct i2c_driver cps226_driver = {
	.driver = {
		.name	= "cps226",
	},
	.probe		= cps226_probe,
	.remove		= cps226_remove,
	.id_table	= cps226_id,

	.class		= I2C_CLASS_SPD,
	.detect		= cps226_detect,
	.address_list	= cps226_i2c,
};

module_i2c_driver(cps226_driver);

MODULE_AUTHOR("RobinLee");
MODULE_DESCRIPTION("cps226 driver");
MODULE_LICENSE("GPL");

4、devicetree配置

devicetree中需要配置四個從裝置的地址,如下,dbf名稱懶得改了:

/dts-v1/;

/ {
	#address-cells = <0x1>;
	#size-cells = <0x1>;
	compatible = "xlnx,zynq-7000";

	cpus {
		#address-cells = <0x1>;
		#size-cells = <0x0>;

		[email protected] {
			compatible = "arm,cortex-a9";
			device_type = "cpu";
			reg = <0x0>;
			clocks = <0x1 0x3>;
			clock-latency = <0x3e8>;
			cpu0-supply = <0x2>;
			operating-points = <0xa4cb8 0xf4240 0x5265c 0xf4240>;
		};

		[email protected] {
			compatible = "arm,cortex-a9";
			device_type = "cpu";
			reg = <0x1>;
			clocks = <0x1 0x3>;
		};
	};

	fpga-full {
		compatible = "fpga-region";
		fpga-mgr = <0x3>;
		#address-cells = <0x1>;
		#size-cells = <0x1>;
		ranges;
	};

	[email protected] {
		compatible = "arm,cortex-a9-pmu";
		interrupts = <0x0 0x5 0x4 0x0 0x6 0x4>;
		interrupt-parent = <0x4>;
		reg = <0xf8891000 0x1000 0xf8893000 0x1000>;
	};

	fixedregulator {
		compatible = "regulator-fixed";
		regulator-name = "VCCPINT";
		regulator-min-microvolt = <0xf4240>;
		regulator-max-microvolt = <0xf4240>;
		regulator-boot-on;
		regulator-always-on;
		linux,phandle = <0x2>;
		phandle = <0x2>;
	};

	amba {
		u-boot,dm-pre-reloc;
		compatible = "simple-bus";
		#address-cells = <0x1>;
		#size-cells = <0x1>;
		interrupt-parent = <0x4>;
		ranges;

		[email protected] {
			compatible = "xlnx,zynq-xadc-1.00.a";
			reg = <0xf8007100 0x20>;
			interrupts = <0x0 0x7 0x4>;
			interrupt-parent = <0x4>;
			clocks = <0x1 0xc>;

			xlnx,channels {
			    #address-cells = <1>;
			    #size-cells = <0>;
			    [email protected] {
				reg = <0>;
			    };
			    [email protected] {
				reg = <1>;
			    };
			    [email protected] {
				reg = <2>;
			    };
 			    [email protected] {
				reg = <3>;
			    };
			    [email protected]{
				reg = <4>;
			    };
			    [email protected]{
				reg = <5>;
			    };
			    [email protected]{
				reg = <6>;
			    };
			   [email protected]{
				reg = <7>;
			    };
			    [email protected] {
				reg = <8>;
			    };
			    [email protected] {
				reg = <9>;
			    };
			    [email protected] {
				reg = <0xa>;
			    };
		    	    [email protected] {
				reg = <0xb>;
			    };
			    [email protected] {
				reg = <0xc>;
			    };
			    [email protected] {
				reg = <0xd>;
			    };
			    [email protected] {
				reg = <0xe>;
			    };
  			    [email protected] {
				reg = <0xf>;
			    };
  			    [email protected] {
				reg = <0x10>;
			    };
        		};
		};


		[email protected] {
			compatible = "xlnx,zynq-gpio-1.0";
			#gpio-cells = <0x2>;
			clocks = <0x1 0x2a>;
			gpio-controller;
			interrupt-controller;
			#interrupt-cells = <0x2>;
			interrupt-parent = <0x4>;
			interrupts = <0x0 0x14 0x4>;
			reg = <0xe000a000 0x1000>;
		};

		[email protected] {
			compatible = "cdns,i2c-r1p10";
			status = "okay";
			clocks = <0x1 0x26>;
			interrupt-parent = <0x4>;
			interrupts = <0x0 0x19 0x4>;
			reg = <0xe0004000 0x1000>;
			#address-cells = <0x1>;
			#size-cells = <0x0>;
			clock-frequency = <0x61a80>;

			[email protected] {
				compatible = "cps1848";
				reg = <0x2>;
			};

			[email protected] {
				compatible = "cps1848";
				reg = <0x4>;
			};

			[email protected] {
				compatible = "cps1848";
				reg = <0x8>;
			};

			[email protected] {
				compatible = "cps226";
				reg = <0x40>;
			};
		};

		[email protected] {
			compatible = "cdns,i2c-r1p10";
			status = "okay";
			clocks = <0x1 0x27>;
			interrupt-parent = <0x4>;
			interrupts = <0x0 0x30 0x4>;
			reg = <0xe0005000 0x1000>;
			#address-cells = <0x1>;
			#size-cells = <0x0>;
			clock-frequency = <0x61a80>;
		};

		[email protected] {
			compatible = "arm,cortex-a9-gic";
			#interrupt-cells = <0x3>;
			interrupt-controller;
			reg = <0xf8f01000 0x1000 0xf8f00100 0x100>;
			num_cpus = <0x2>;
			num_interrupts = <0x60>;
			linux,phandle = <0x4>;
			phandle = <0x4>;
		};

		[email protected] {
			compatible = "arm,pl310-cache";
			reg = <0xf8f02000 0x1000>;
			interrupts = <0x0 0x2 0x4>;
			arm,data-latency = <0x3 0x2 0x2>;
			arm,tag-latency = <0x2 0x2 0x2>;
			cache-unified;
			cache-level = <0x2>;
		};

		[email protected] {
			compatible = "xlnx,zynq-ddrc-a05";
			reg = <0xf8006000 0x1000>;
		};

		[email protected] {
			compatible = "xlnx,zynq-ocmc-1.0";
			interrupt-parent = <0x4>;
			interrupts = <0x0 0x3 0x4>;
			reg = <0xf800c000 0x1000>;
		};

		[email protected] {
			compatible = "xlnx,xuartps", "cdns,uart-r1p8";
			status = "okay";
			clocks = <0x1 0x17 0x1 0x28>;
			clock-names = "uart_clk", "pclk";
			reg = <0xe0000000 0x1000>;
			interrupts = <0x0 0x1b 0x4>;
			device_type = "serial";
			port-number = <0x0>;
		};

		[email protected] {
			compatible = "xlnx,zynq-spi-r1p6";
			reg = <0xe0006000 0x1000>;
			status = "okay";
			interrupt-parent = <0x4>;
			interrupts = <0x0 0x1a 0x4>;
			clocks = <0x1 0x19 0x1 0x22>;
			clock-names = "ref_clk", "pclk";
			#address-cells = <0x1>;
			#size-cells = <0x0>;
			is-decoded-cs = <0x0>;
			num-cs = <0x3>;
		};

		[email protected] {
			compatible = "xlnx,zynq-spi-r1p6";
			reg = <0xe0007000 0x1000>;
			status = "okay";
			interrupt-parent = <0x4>;
			interrupts = <0x0 0x31 0x4>;
			clocks = <0x1 0x1a 0x1 0x23>;
			clock-names = "ref_clk", "pclk";
			#address-cells = <0x1>;
			#size-cells = <0x0>;
			is-decoded-cs = <0x0>;
			num-cs = <0x3>;

			[email protected] {
				compatible = "micron,n25q128a11","jedec,spi-nor";
				reg = <0x1>;
				spi-max-frequency = <0x9EF21B0>;
				spi-tx-bus-width = <0x1>;
				spi-rx-bus-width = <0x1>;
				#address-cells = <0x1>;
				#size-cells = <0x1>;

				[email protected] {
					label = "spi-flash";
					reg = <0x0 0x1000000>;
				};
			};
		};

		[email protected] {
			clock-names = "ref_clk", "pclk";
			clocks = <0x1 0xa 0x1 0x2b>;
			compatible = "xlnx,zynq-qspi-1.0";
			status = "okay";
			interrupt-parent = <0x4>;
			interrupts = <0x0 0x13 0x4>;
			reg = <0xe000d000 0x1000>;
			#address-cells = <0x1>;
			#size-cells = <0x0>;
			is-dual = <0x1>;
			num-cs = <0x1>;
		};

		[email protected] {
			compatible = "xlnx,ps7-ethernet-1.00.a";
			reg = <0xe000b000 0x1000>;
			status = "okay";
			interrupt-parent = <0x3>;
			interrupts = <0x0 0x16 0x4>;
			clocks = <0x1 0xd 0x1 0x1e>;
			clock-names = "ref_clk", "aper_clk";
			#address-cells = <0x1>;
			#size-cells = <0x0>;
			enet-reset = <0x4 0x2f 0x0>;
			local-mac-address = [00 0a 35 00 00 00];
			phy-mode = "rgmii";
			phy-handle = <0x5>;
			xlnx,eth-mode = <0x1>;
			xlnx,has-mdio = <0x1>;
			xlnx,ptp-enet-clock = <0x69f6bcb>;

			mdio {
				#address-cells = <0x1>;
				#size-cells = <0x0>;

				[email protected] {
					compatible = "marvell,88e1111";
					device_type = "ethernet-phy";
					reg = <0x4>;
					linux,phandle = <0x7>;
					phandle = <0x7>;
				};
			};
		};

		[email protected] {
			#address-cells = <0x1>;
			#size-cells = <0x1>;
			compatible = "xlnx,zynq-slcr", "syscon", "simple-mfd";
			reg = <0xf8000000 0x1000>;
			ranges;
			linux,phandle = <0x5>;
			phandle = <0x5>;

			[email protected] {
				#clock-cells = <0x1>;
				compatible = "xlnx,ps7-clkc";
				fclk-enable = <0x1>;
				clock-output-names = "armpll", "ddrpll", "iopll", "cpu_6or4x", "cpu_3or2x", "cpu_2x", "cpu_1x", "ddr2x", "ddr3x", "dci", "lqspi", "smc", "pcap", "gem0", "gem1", "fclk0", "fclk1", "fclk2", "fclk3", "can0", "can1", "sdio0", "sdio1", "uart0", "uart1", "spi0", "spi1", "dma", "usb0_aper", "usb1_aper", "gem0_aper", "gem1_aper", "sdio0_aper", "sdio1_aper", "spi0_aper", "spi1_aper", "can0_aper", "can1_aper", "i2c0_aper", "i2c1_aper", "uart0_aper", "uart1_aper", "gpio_aper", "lqspi_aper", "smc_aper", "swdt", "dbg_trc", "dbg_apb";
				reg = <0x100 0x100>;
				ps-clk-frequency = <0x2faf080>;
				linux,phandle = <0x1>;
				phandle = <0x1>;
			};

			[email protected] {
				compatible = "xlnx,zynq-reset";
				reg = <0x200 0x48>;
				#reset-cells = <0x1>;
				syscon = <0x5>;
			};

			[email protected] {
				compatible = "xlnx,pinctrl-zynq";
				reg = <0x700 0x200>;
				syscon = <0x5>;
			};
		};

		[email protected] {
			compatible = "arm,pl330", "arm,primecell";
			reg = <0xf8003000 0x1000>;
			interrupt-parent = <0x4>;
			interrupt-names = "abort", "dma0", "dma1", "dma2", "dma3", "dma4", "dma5", "dma6", "dma7";
			interrupts = <0x0 0xd 0x4 0x0 0xe 0x4 0x0 0xf 0x4 0x0 0x10 0x4 0x0 0x11 0x4 0x0 0x28 0x4 0x0 0x29 0x4 0x0 0x2a 0x4 0x0 0x2b 0x4>;
			#dma-cells = <0x1>;
			#dma-channels = <0x8>;
			#dma-requests = <0x4>;
			clocks = <0x1 0x1b>;
			clock-names = "apb_pclk";
		};

		[email protected] {
			compatible = "xlnx,zynq-devcfg-1.0";
			interrupt-parent = <0x4>;
			interrupts = <0x0 0x8 0x4>;
			reg = <0xf8007000 0x100>;
			clocks = <0x1 0xc 0x1 0xf 0x1 0x10 0x1 0x11 0x1 0x12>;
			clock-names = "ref_clk", "fclk0", "fclk1", "fclk2", "fclk3";
			syscon = <0x5>;
			linux,phandle = <0x3>;
			phandle = <0x3>;
		};

		[email protected] {
			compatible = "xlnx,zynq-efuse";
			reg = <0xf800d000 0x20>;
		};

		[email protected] {
			compatible = "arm,cortex-a9-global-timer";
			reg = <0xf8f00200 0x20>;
			interrupts = <0x1 0xb 0x301>;
			interrupt-parent = <0x4>;
			clocks = <0x1 0x4>;
		};

		[email protected] {
			interrupt-parent = <0x4>;
			interrupts = <0x0 0xa 0x4 0x0 0xb 0x4 0x0 0xc 0x4>;
			compatible = "cdns,ttc";
			clocks = <0x1 0x6>;
			reg = <0xf8001000 0x1000>;
		};

		[email protected] {
			interrupt-parent = <0x4>;
			interrupts = <0x0 0x25 0x4 0x0 0x26 0x4 0x0 0x27 0x4>;
			compatible = "cdns,ttc";
			clocks = <0x1 0x6>;
			reg = <0xf8002000 0x1000>;
		};

		[email protected] {
			interrupt-parent = <0x4>;
			interrupts = <0x1 0xd 0x301>;
			compatible = "arm,cortex-a9-twd-timer";
			reg = <0xf8f00600 0x20>;
			clocks = <0x1 0x4>;
		};

		[email protected] {
			clocks = <0x1 0x2d>;
			compatible = "cdns,wdt-r1p2";
			interrupt-parent = <0x4>;
			interrupts = <0x0 0x9 0x1>;
			reg = <0xf8005000 0x1000>;
			timeout-sec = <0xa>;
		};
	};

	chosen {
		bootargs = "earlycon";
		stdout-path = "serial0:115200n8";
	};

	aliases {
		ethernet0 = "/amba/[email protected]";
		serial0 = "/amba/[email protected]";
		spi0 = "/amba/[email protected]";
		spi1 = "/amba/[email protected]";
		spi2 = "/amba/[email protected]";
	};

	memory {
		device_type = "memory";
		reg = <0x0 0x40000000>;
	};
};

5、應用示例

應用可以參考1848那樣提供讀寫暫存器介面函式,這裡要注意資料高低位轉換問題,是否需要使用htonl函式,不同的晶片要求不一樣。

DBF晶片程式碼如下:

/*
 * cps1848.h
 *
 *  Created on: 2018年9月8日
 *      Author: Administrator
 */

#ifndef SRC_CPS1848_H_
#define SRC_CPS1848_H_

int Init_1848();
unsigned int get_1848_reg(int num,unsigned int offset);
void set_1848_reg(int num,unsigned int offset, unsigned int data);


#endif /* SRC_CPS1848_H_ */
/*
 * Copyright (c) 2016 CGT Co., Ltd.
 *
 * Authors: Robin Lee <[email protected]>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program;
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <memory.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/poll.h>
#include <sys/time.h>
#include <sys/socket.h>

#include <fcntl.h>
#include <errno.h>
#include <pthread.h>
#include <math.h>
#include <unistd.h>
#include <signal.h>

#include <termios.h>
#include <netinet/in.h>

#include "cps1848.h"

/*---------------------------------------------------------------------------------------------------------------------------------------------------
 * global vars
 */
#define FP_DEV_1 "/sys/class/i2c-dev/i2c-0/device/0-0002/eeprom"
#define FP_DEV_2 "/sys/class/i2c-dev/i2c-0/device/0-0004/eeprom"
#define FP_DEV_3 "/sys/class/i2c-dev/i2c-0/device/0-0008/eeprom"

static int global_fd_1 = -1;
static int global_fd_2 = -1;
static int global_fd_3 = -1;

//operations of cps1848
int fd_initial(int num)
{

	int fd = -1;

	/*
		Open modem device for reading and writing and not as controlling tty
		because we don't want to get killed if linenoise sends CTRL-C.
	*/
	if(num==0)
	{
		printf("Open '%s' .. ", FP_DEV_1);
		fd = open(FP_DEV_1, O_RDWR );
	}
	else if(num==1)
	{
		printf("Open '%s' .. ", FP_DEV_2);
		fd = open(FP_DEV_2, O_RDWR );
	}
	else if(num==2)
	{
		printf("Open '%s' .. ", FP_DEV_3);
		fd = open(FP_DEV_3, O_RDWR );
	}
	else
	{
		printf("Open error.\n");
		return -1;
	}

	if (fd <0) {
		printf("failed (err = %d)\n", fd);
		return -1;
	}

	printf("Done\n");

	return fd;
}

int fd_exit(int fd,int num)
{
	if(num==1)
	{
		printf("Close '%s' .. ", FP_DEV_1);
	}
	else if(num==2)
	{
		printf("Close '%s' .. ", FP_DEV_2);
	}
	else
	{
		printf("Close '%s' .. ", FP_DEV_3);
	}
	close(fd);

	printf("Done\n");

	return 0;
}

/*---------------------------------------------------------------------------------------------------------------------------------------------------
 * get_1848_reg, set_1848_reg
 */
unsigned int get_1848_reg(int num,unsigned int offset)
{
	unsigned int value = 0xffff;
	unsigned int ans=0;
	int fd=-1;
	if(num==0)
	{
		fd=global_fd_1;
	}
	else if(num==1)
	{
		fd=global_fd_2;
	}
	else if( num==2 )
	{
		fd=global_fd_3;
	}
	else
	{
		printf("get_dbf_reg::Invalid param !\n");
		return 0;
	}

	if (fd<0) {
		printf("Invalid device handle !\n");
		return value;
	}

	if( lseek(fd, offset, SEEK_SET) == (off_t) -1 ) {
		printf("failed for seek to offset 0x%x !\n", offset);
		return value;
	}

	if ( read(fd, &value, sizeof(value)) != sizeof(value)) {
		printf("failed for read from offset 0x%x !\n", offset);
		return value;
	}
	//ans=htonl(value);
	return value;
}

void set_1848_reg(int num,unsigned int offset, unsigned int data)
{
	unsigned int value = data;
	int fd=-1;
	if(num==0)
	{
		fd=global_fd_1;
	}
	else if(num==1)
	{
		fd=global_fd_2;
	}
	else if( num==2 )
	{
		fd=global_fd_3;
	}
	else
	{
		printf("set_dbf_reg::Invalid param !\n");
		return;
	}
	if (fd<0) {
		printf("Invalid device handle !\n");
		return ;
	}

	if( lseek(fd, offset, SEEK_SET) == (off_t) -1 ) {
		printf("failed for seek to offset 0x%x !\n", offset);
		return ;
	}

	if ( write(fd, &value, sizeof(value)) != sizeof(value)) {
//		printf("failed for write from offset 0x%x !\n", offset);
		return ;
	}
	return ;
}

unsigned int regtoul(const char *str)
{
	int cbase = 10;
	if(str[0]=='0'&&(str[1]=='x'||str[1]=='X')) {
		cbase = 16;
	}
	return strtoul(str, NULL, cbase);
}

int Init_1848()
{
		global_fd_1 = fd_initial(0);
		global_fd_2 = fd_initial(1);
		global_fd_3 = fd_initial(2);
		if (global_fd_1<0) {
			printf("\n Invalid First dbf device ! \n");
			return -1;
		}
		if (global_fd_2<0) {
			printf("\n Invalid Second dbf device ! \n");
			return -1;
		}
		if (global_fd_3<0) {
			printf("\n Invalid Third dbf device ! \n");
			return -1;
		}
		return 0;
}


Ti 226晶片讀寫介面如下

/*
 * cps1848.h
 *
 *  Created on: 2018年9月8日
 *      Author: Administrator
 */

#ifndef SRC_CPS226_H_
#define SRC_CPS226_H_

int Init_226();
unsigned int get_226_reg(unsigned int offset);
void set_226_reg(unsigned int offset, unsigned int data);


#endif /* SRC_CPS1848_H_ */
/*
 * Copyright (c) 2016 CGT Co., Ltd.
 *
 * Authors: Robin Lee <[email protected]>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program;
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <memory.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/poll.h>
#include <sys/time.h>
#include <sys/socket.h>

#include <fcntl.h>
#include <errno.h>
#include <pthread.h>
#include <math.h>
#include <unistd.h>
#include <signal.h>

#include <termios.h>
#include <netinet/in.h>

#include "cps226.h"

/*---------------------------------------------------------------------------------------------------------------------------------------------------
 * global vars
 */
#define FP_DEV "/sys/class/i2c-dev/i2c-0/device/0-0040/eeprom"


static int global_fd = -1;

//operations of cps1848
int fd_initial_226()
{
	int fd = -1;
	/*
		Open modem device for reading and writing and not as controlling tty
		because we don't want to get killed if linenoise sends CTRL-C.
	*/
	printf("Open '%s' .. ", FP_DEV);
	fd = open(FP_DEV, O_RDWR );

	if (fd <0) {
		printf("failed (err = %d)\n", fd);
		return -1;
	}

	printf("Done\n");

	return fd;
}

int fd_exit_226(int fd)
{
	close(fd);
	printf("Done\n");

	return 0;
}

/*---------------------------------------------------------------------------------------------------------------------------------------------------
 * get_1848_reg, set_1848_reg
 */
unsigned int get_226_reg(unsigned int offset)
{
	unsigned int value = 0xffff;
	unsigned int ans=0;
	int fd=-1;
	fd=global_fd;

	if (fd<0) {
		printf("Invalid device handle !\n");
		return value;
	}

	if( lseek(fd, offset, SEEK_SET) == (off_t) -1 ) {
		printf("failed for seek to offset 0x%x !\n", offset);
		return value;
	}

	if ( read(fd, &value, sizeof(value)) != sizeof(value)) {
		printf("failed for read from offset 0x%x !\n", offset);
		return value;
	}
	ans=htonl(value);
	return ans>>16;
}

void set_226_reg(unsigned int offset, unsigned int data)
{
	unsigned int value = data;
	int fd=-1;
	fd=global_fd;
	if (fd<0) {
		printf("Invalid device handle !\n");
		return ;
	}

	if( lseek(fd, offset, SEEK_SET) == (off_t) -1 ) {
		printf("failed for seek to offset 0x%x !\n", offset);
		return ;
	}

	if ( write(fd, &value, sizeof(value)) != sizeof(value)) {
//		printf("failed for write from offset 0x%x !\n", offset);
		return ;
	}
	return ;
}

unsigned int regtoul_226(const char *str)
{
	int cbase = 10;
	if(str[0]=='0'&&(str[1]=='x'||str[1]=='X')) {
		cbase = 16;
	}
	return strtoul(str, NULL, cbase);
}

int Init_226()
{
	global_fd = fd_initial_226();
	if (global_fd<0)
	{
		printf("\n Invalid 226 device ! \n");
		return -1;
	}
	return 0;
}


6、測試說明

Linux啟動過程中能看到驅動正確載入,顯然裝置都找到了。

啟動應用後能讀出DBF晶片原來的ID,並根據槽位號配置新的ID

程式碼如下:

/*
 * config_dbf.c
 *
 *  Created on: 2018年8月17日
 *      Author: Administrator
 */


#include "config_dbf.h"
#include "gpio.h"
#include "cps1848.h"

extern unsigned int ga_chass;

int config_dbf_id()
{
	unsigned int _data;
	u32 chip_id;

	printf("Change dbf id start\n");

	printf("------------Set DBFA ID Register------------\n");
	_data=get_1848_reg(0,0);
	printf("orignial DBFA ID  = 0x%x\n",_data);

    chip_id = (ga_chass<<4) | 0x1;
    set_1848_reg(0,0,chip_id);

    _data=get_1848_reg(0,0);
	printf("config DBFA ID  = 0x%x\n",_data);


	printf("------------Set DBFB ID Register------------\n");
	_data=get_1848_reg(1,0);
	printf("orignial DBFB ID  = 0x%x\n",_data);

	chip_id = (ga_chass<<4) | 0x2;
	set_1848_reg(1,0,chip_id);

	_data=get_1848_reg(1,0);
	printf("config DBFB ID  = 0x%x\n",_data);


	printf("------------Set DBFC ID Register------------\n");
	_data=get_1848_reg(2,0);
	printf("orignial DBFC ID  = 0x%x\n",_data);

	chip_id = (ga_chass<<4) | 0x3;
	set_1848_reg(2,0,chip_id);

	_data=get_1848_reg(2,0);
	printf("config DBFC ID  = 0x%x\n",_data);

	return 0;
}

int read_dbf_id()
{
	unsigned int _data;
	_data=get_1848_reg(0,0);
	printf("DBFA ID  = 0x%x\n",_data);//true data is 1002

	_data=get_1848_reg(1,0);
	printf("DBFB ID   = 0x%x\n",_data);//true data is 1003

	_data=get_1848_reg(2,0);
	printf("DBFC ID   = 0x%x\n",_data);//true data is 1004
	return 0;
}

int change_dbf_uart(int id)
{
	if(id==0)
	{
		SetGpioReg(GPIO_UAET_SELECT_BASE_ADDR,0x0,0);
	}
	else if(id==1)
	{
		SetGpioReg(GPIO_UAET_SELECT_BASE_ADDR,0x0,1);
	}
	else
	{
		SetGpioReg(GPIO_UAET_SELECT_BASE_ADDR,0x0,2);
	}
	return 0;
}

#if 0
int bit_226()
{
	unsigned int val32;
	unsigned short val16;
	unsigned int _data;
	float TempData;
	int Status;

	int ret=0;

	ret=IICRead_Reg(IIC_SLAVE_ADDR_226,0x05,&_data);
	if(ret<0)
	{
		goto error;
	}
	ret=IICWrite_Reg(IIC_SLAVE_ADDR_226,0x05,0x1400);
	if(ret<0)
	{
		goto error;
	}
	ret=IICRead_Reg(IIC_SLAVE_ADDR_226,0x05,&_data);
	if(ret<0)
	{
		goto error;
	}
	ret=IICWrite_Reg(IIC_SLAVE_ADDR_226,0x02,0x1400);
	if(ret<0)
	{
		goto error;
	}
	ret=IICRead_Reg(IIC_SLAVE_ADDR_226,0x05,&_data);
	if(ret<0)
	{
		goto error;
	}
	val32=_data;
	val16=(val32)&0xFFFF;

	ret=IICRead_Reg(IIC_SLAVE_ADDR_226,0x02,&_data);
	if(ret<0)
	{
		goto error;
	}
	val32=_data;
	val16=(val32)&0xFFFF;
	TempData = val16*1.0/1000.0;
	printf("bus voltage is %f V.\n", TempData);

	ret=IICRead_Reg(IIC_SLAVE_ADDR_226,0x04,&_data);
	if(ret<0)
	{
		goto error;
	}

	val32=_data;
	val16=(val32)&0xFFFF;
	TempData = val16*1.0/1000.0;
	printf("bus current is %f A.\n", TempData);

	if(TempData>=15.0)
	{
		printf("-----safe_rst because of Current----\n");
		SetGpioReg(GPIO_DBF_RESET_ADDR,0x0,1);
		SetGpioReg(GPIO_DBF_RESET_ADDR,0x0,0);
	}

	ret=IICRead_Reg(IIC_SLAVE_ADDR_226,0x03,&_data);
	if(ret<0)
	{
		goto error;
	}

	val32=_data;
	val16=(val32)&0xFFFF;
	TempData = val16*25.0/1000.0;
	printf("power is %f W.\n", TempData);

	return 0;

error:
	return -1;
}
#endif

Ti 226晶片也能讀出功耗了

讀功耗程式碼如下:

#include <stdio.h>

#include "bit.h"
#include "config_dbf.h"
#include "gpio.h"
#include "cps226.h"

extern unsigned int g_temp[10];
extern unsigned int g_vcc[9];
extern unsigned int g_vcc_aux[16];


void Show_226_bit()
{
	unsigned int _data,val32;
	unsigned short val16;
	float temp;

	_data=get_226_reg(0x05);
	set_226_reg(0x05,0x14);
	_data=get_226_reg(0x05);

	set_226_reg(0x02,0x14);
	val32=get_226_reg(0x05);
	val16=val32&0xffff;


	val32 = get_226_reg(0x02);
	val16 = (val32)&0xFFFF;
	temp = val16*1.25/1000.0;
	printf("bus voltage is %.3f V. \n",temp);

	val32 = get_226_reg(0x04);
	val16 = (val32)&0xFFFF;

	temp = val16*1.0/1000.0;
	printf("Current is %.3f A. \n", temp);

	if(temp>=15)
	{
		printf("Warning!!! DBF Current Amp Alarm! Reset DBF NOW!!!\n");
		SetGpioReg(GPIO_DBF_RESET_ADDR,0,0x1);
		SetGpioReg(GPIO_DBF_RESET_ADDR,0,0x0);
	}

	val32 = get_226_reg(0x03);
	val16 = (val32)&0xFFFF ;
	temp = val16*25.0/1000.0;
	printf("Power is %.3f W. \r\n", temp);
}

至此I2C驅動除錯結束。