当前位置:   article > 正文

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了。

代码分别如下

  1. /*
  2. * CPS1848 bus driver
  3. *
  4. * Copyright (C) 2014 CGT Corp.
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; version 2 of the License.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; if not, write to the Free Software
  17. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  18. *
  19. */
  20. #define DEBUG
  21. #include <linux/kernel.h>
  22. #include <linux/module.h>
  23. #include <linux/slab.h>
  24. #include <linux/i2c.h>
  25. #include <linux/mutex.h>
  26. #include <linux/delay.h>
  27. #include <linux/serial_core.h>
  28. /* Each client has this additional data */
  29. #define USER_EEPROM_SIZE 0xFFFF48
  30. #define USER_XFER_MAX_COUNT 0x8
  31. /* Addresses to scan */
  32. static const unsigned short cps1848_i2c[] = { 0x3, I2C_CLIENT_END };
  33. static unsigned read_timeout = 25;
  34. module_param(read_timeout, uint, 0);
  35. MODULE_PARM_DESC(read_timeout, "Time (in ms) to try reads (default 25)");
  36. static unsigned write_timeout = 25;
  37. module_param(write_timeout, uint, 0);
  38. MODULE_PARM_DESC(write_timeout, "Time (in ms) to try writes (default 25)");
  39. struct cps1848_data {
  40. struct mutex lock;
  41. u8 *data;
  42. };
  43. static ssize_t cps1848_eeprom_read( struct i2c_client *client,
  44. char *buf, unsigned offset, size_t count)
  45. {
  46. struct i2c_msg msg[2];
  47. u8 msgbuf[4];
  48. unsigned long timeout, transfer_time;
  49. int status;
  50. memset(msg, 0, sizeof(msg));
  51. //msgbuf[0] = (u8)((offset >> 18) & 0x3f);
  52. //msgbuf[1] = (u8)((offset >> 10) & 0xff);
  53. //msgbuf[2] = (u8)((offset >> 2) & 0xff);
  54. msgbuf[0] = 0x04;
  55. msgbuf[1] = 0x00;
  56. msg[0].addr = client->addr;
  57. msg[0].buf = msgbuf;
  58. msg[0].len = 2;
  59. msg[1].addr = client->addr;
  60. msg[1].flags = I2C_M_RD;
  61. msg[1].buf = buf;
  62. msg[1].len = count;
  63. /*
  64. * Reads fail if the previous write didn't complete yet. We may
  65. * loop a few times until this one succeeds, waiting at least
  66. * long enough for one entire page write to work.
  67. */
  68. timeout = jiffies + msecs_to_jiffies(read_timeout);
  69. do {
  70. transfer_time = jiffies;
  71. status = i2c_transfer(client->adapter, msg, 2);
  72. if (status == 2)
  73. status = count;
  74. dev_dbg(&client->dev, "read %ld@0x%lx --> %d (%ld)\n",
  75. count, (unsigned long)offset, status, jiffies);
  76. if (status == count)
  77. return count;
  78. /* REVISIT: at HZ=100, this is sloooow */
  79. msleep(1);
  80. } while (time_before(transfer_time, timeout));
  81. return -ETIMEDOUT;
  82. }
  83. static ssize_t cps1848_read(struct file *filp, struct kobject *kobj,
  84. struct bin_attribute *bin_attr,
  85. char *buf, loff_t offset, size_t count)
  86. {
  87. struct i2c_client *client = kobj_to_i2c_client(kobj);
  88. struct cps1848_data *data = i2c_get_clientdata(client);
  89. ssize_t retval = 0;
  90. if (offset > USER_EEPROM_SIZE)
  91. return 0;
  92. if (offset + count > USER_EEPROM_SIZE)
  93. count = USER_EEPROM_SIZE - offset;
  94. mutex_lock(&data->lock);
  95. dev_dbg(&client->dev, "cps1848 start read %ld@0x%lx ..\n", count, (unsigned long)offset);
  96. while (count > 0) {
  97. ssize_t status = count>USER_XFER_MAX_COUNT?USER_XFER_MAX_COUNT:count;
  98. status = cps1848_eeprom_read(client, buf, offset, status);
  99. if (status <= 0) {
  100. if (retval == 0)
  101. retval = status;
  102. break;
  103. }
  104. buf += status;
  105. offset += status;
  106. count -= status;
  107. retval += status;
  108. }
  109. dev_dbg(&client->dev, "cps1848 end read %ld@0x%lx !\n", retval, (unsigned long)offset);
  110. mutex_unlock(&data->lock);
  111. return retval;
  112. }
  113. static ssize_t cps1848_eeprom_write(
  114. struct i2c_client *client,
  115. struct cps1848_data *data,
  116. char *buf, unsigned offset, size_t count)
  117. {
  118. struct i2c_msg msg[1];
  119. u8 *msgbuf;
  120. unsigned long timeout, transfer_time;
  121. int status;
  122. memset(msg, 0, sizeof(msg));
  123. msgbuf = data->data;
  124. // msgbuf[0] = (u8)((offset >> 18) & 0x3f);
  125. // msgbuf[1] = (u8)((offset >> 10) & 0xff);
  126. // msgbuf[2] = (u8)((offset >> 2) & 0xff);
  127. msgbuf[0] = 0x04;
  128. msgbuf[1] = 0x00;
  129. memcpy(msgbuf+2, buf, count);
  130. msg[0].addr = client->addr;
  131. msg[0].buf = msgbuf;
  132. msg[0].len = 2 + count;
  133. /*
  134. * Reads fail if the previous write didn't complete yet. We may
  135. * loop a few times until this one succeeds, waiting at least
  136. * long enough for one entire page write to work.
  137. */
  138. timeout = jiffies + msecs_to_jiffies(write_timeout);
  139. do {
  140. transfer_time = jiffies;
  141. status = i2c_transfer(client->adapter, msg, 1);
  142. if (status == 1)
  143. status = count;
  144. dev_dbg(&client->dev, "write %ld@0x%lx --> %d (%ld)\n",
  145. count, (unsigned long)offset, status, jiffies);
  146. if (status == count)
  147. return count;
  148. /* REVISIT: at HZ=100, this is sloooow */
  149. msleep(1);
  150. } while (time_before(transfer_time, timeout));
  151. return -ETIMEDOUT;
  152. }
  153. static ssize_t cps1848_write(struct file *filp, struct kobject *kobj,
  154. struct bin_attribute *bin_attr,
  155. char *buf, loff_t offset, size_t count)
  156. {
  157. struct i2c_client *client = kobj_to_i2c_client(kobj);
  158. struct cps1848_data *data = i2c_get_clientdata(client);
  159. ssize_t retval = 0;
  160. if (offset > USER_EEPROM_SIZE)
  161. return 0;
  162. if (offset + count > USER_EEPROM_SIZE)
  163. count = USER_EEPROM_SIZE - offset;
  164. mutex_lock(&data->lock);
  165. dev_dbg(&client->dev, "cps1848 start write %ld@0x%lx ..\n", count, (unsigned long)offset);
  166. while (count > 0) {
  167. ssize_t status = count>USER_XFER_MAX_COUNT?USER_XFER_MAX_COUNT:count;
  168. status = cps1848_eeprom_write(client, data, buf, offset, status);
  169. if (status <= 0) {
  170. if (retval == 0)
  171. retval = status;
  172. break;
  173. }
  174. buf += status;
  175. offset += status;
  176. count -= status;
  177. retval += status;
  178. }
  179. dev_dbg(&client->dev, "cps1848 end write %ld@0x%lx !\n", retval, (unsigned long)offset);
  180. mutex_unlock(&data->lock);
  181. return retval;
  182. }
  183. static struct bin_attribute user_eeprom_attr = {
  184. .attr = {
  185. .name = "eeprom",
  186. .mode = (S_IRUSR | S_IWUSR),
  187. },
  188. .size = USER_EEPROM_SIZE,
  189. .read = cps1848_read,
  190. .write = cps1848_write,
  191. };
  192. /* Return 0 if detection is successful, -ENODEV otherwise */
  193. static int cps1848_detect(struct i2c_client *client, struct i2c_board_info *info)
  194. {
  195. struct i2c_adapter *adapter = client->adapter;
  196. if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
  197. dev_dbg(&client->dev, "cps1848 detect error for BYTE access !\n");
  198. return -ENODEV;
  199. }
  200. strlcpy(info->type, "eeprom", I2C_NAME_SIZE);
  201. return 0;
  202. }
  203. static int cps1848_probe(struct i2c_client *client,
  204. const struct i2c_device_id *id)
  205. {
  206. struct i2c_adapter *adapter = client->adapter;
  207. struct cps1848_data *data;
  208. int err ;
  209. dev_notice(&client->dev, "CPS1848 driver\n" );
  210. if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
  211. dev_err(&client->dev, "CPS1848 driver: BYTE DATA not supported! \n" );
  212. return -ENODEV;
  213. }
  214. if (!(data = kzalloc(sizeof(struct cps1848_data), GFP_KERNEL))) {
  215. dev_err(&client->dev, "CPS1848 driver: Memory alloc error ! \n" );
  216. return -ENOMEM;
  217. }
  218. /* alloc buffer */
  219. data->data = devm_kzalloc(&client->dev, USER_XFER_MAX_COUNT + 8, GFP_KERNEL);
  220. if (!data->data) {
  221. dev_err(&client->dev, "CPS1848 driver: Memory alloc error ! \n" );
  222. err = -ENOMEM;
  223. goto exit_kfree;
  224. }
  225. /* Init real i2c_client */
  226. i2c_set_clientdata(client, data);
  227. mutex_init(&data->lock);
  228. err = sysfs_create_bin_file(&client->dev.kobj, &user_eeprom_attr);
  229. if (err) {
  230. dev_err(&client->dev, "CPS1848 driver: sysfs create error ! \n" );
  231. goto exit_kfree;
  232. }
  233. return 0;
  234. exit_kfree:
  235. if(data->data)
  236. kfree(data->data);
  237. kfree(data);
  238. return err;
  239. }
  240. static int cps1848_remove(struct i2c_client *client)
  241. {
  242. struct cps1848_data *data = i2c_get_clientdata(client);
  243. sysfs_remove_bin_file(&client->dev.kobj, &user_eeprom_attr);
  244. if(data->data)
  245. kfree(data->data);
  246. kfree(data);
  247. return 0;
  248. }
  249. static const struct i2c_device_id cps1848_id[] = {
  250. { "cps1848", 0 },
  251. { }
  252. };
  253. MODULE_DEVICE_TABLE(i2c, cps1848_id);
  254. static struct i2c_driver cps1848_driver = {
  255. .driver = {
  256. .name = "cps1848",
  257. },
  258. .probe = cps1848_probe,
  259. .remove = cps1848_remove,
  260. .id_table = cps1848_id,
  261. .class = I2C_CLASS_SPD,
  262. .detect = cps1848_detect,
  263. .address_list = cps1848_i2c,
  264. };
  265. module_i2c_driver(cps1848_driver);
  266. MODULE_AUTHOR("RobinLee");
  267. MODULE_DESCRIPTION("CPS1848 driver");
  268. MODULE_LICENSE("GPL");
  1. /*
  2. * cps226 bus driver
  3. *
  4. * Copyright (C) 2014 CGT Corp.
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; version 2 of the License.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; if not, write to the Free Software
  17. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  18. *
  19. */
  20. #define DEBUG
  21. #include <linux/kernel.h>
  22. #include <linux/module.h>
  23. #include <linux/slab.h>
  24. #include <linux/i2c.h>
  25. #include <linux/mutex.h>
  26. #include <linux/delay.h>
  27. #include <linux/serial_core.h>
  28. /* Each client has this additional data */
  29. #define USER_EEPROM_SIZE 0xFFFF48
  30. #define USER_XFER_MAX_COUNT 0x8
  31. /* Addresses to scan */
  32. static const unsigned short cps226_i2c[] = { 0x3, I2C_CLIENT_END };
  33. static unsigned read_timeout = 25;
  34. module_param(read_timeout, uint, 0);
  35. MODULE_PARM_DESC(read_timeout, "Time (in ms) to try reads (default 25)");
  36. static unsigned write_timeout = 25;
  37. module_param(write_timeout, uint, 0);
  38. MODULE_PARM_DESC(write_timeout, "Time (in ms) to try writes (default 25)");
  39. struct cps226_data {
  40. struct mutex lock;
  41. u8 *data;
  42. };
  43. static ssize_t cps226_eeprom_read( struct i2c_client *client,
  44. char *buf, unsigned offset, size_t count)
  45. {
  46. struct i2c_msg msg[2];
  47. u8 msgbuf[4];
  48. unsigned long timeout, transfer_time;
  49. int status;
  50. memset(msg, 0, sizeof(msg));
  51. msgbuf[0] = (u8)(offset & 0xff);
  52. msg[0].addr = client->addr;
  53. msg[0].buf = msgbuf;
  54. msg[0].len = 1;
  55. msg[1].addr = client->addr;
  56. msg[1].flags = I2C_M_RD;
  57. msg[1].buf = buf;
  58. msg[1].len = count;
  59. /*
  60. * Reads fail if the previous write didn't complete yet. We may
  61. * loop a few times until this one succeeds, waiting at least
  62. * long enough for one entire page write to work.
  63. */
  64. timeout = jiffies + msecs_to_jiffies(read_timeout);
  65. do {
  66. transfer_time = jiffies;
  67. status = i2c_transfer(client->adapter, msg, 2);
  68. if (status == 2)
  69. status = count;
  70. dev_dbg(&client->dev, "read %ld@0x%lx --> %d (%ld)\n",
  71. count, (unsigned long)offset, status, jiffies);
  72. if (status == count)
  73. return count;
  74. /* REVISIT: at HZ=100, this is sloooow */
  75. msleep(1);
  76. } while (time_before(transfer_time, timeout));
  77. return -ETIMEDOUT;
  78. }
  79. static ssize_t cps226_read(struct file *filp, struct kobject *kobj,
  80. struct bin_attribute *bin_attr,
  81. char *buf, loff_t offset, size_t count)
  82. {
  83. struct i2c_client *client = kobj_to_i2c_client(kobj);
  84. struct cps226_data *data = i2c_get_clientdata(client);
  85. ssize_t retval = 0;
  86. if (offset > USER_EEPROM_SIZE)
  87. return 0;
  88. if (offset + count > USER_EEPROM_SIZE)
  89. count = USER_EEPROM_SIZE - offset;
  90. mutex_lock(&data->lock);
  91. dev_dbg(&client->dev, "cps226 start read %ld@0x%lx ..\n", count, (unsigned long)offset);
  92. while (count > 0) {
  93. ssize_t status = count>USER_XFER_MAX_COUNT?USER_XFER_MAX_COUNT:count;
  94. status = cps226_eeprom_read(client, buf, offset, status);
  95. if (status <= 0) {
  96. if (retval == 0)
  97. retval = status;
  98. break;
  99. }
  100. buf += status;
  101. offset += status;
  102. count -= status;
  103. retval += status;
  104. }
  105. dev_dbg(&client->dev, "cps226 end read %ld@0x%lx !\n", retval, (unsigned long)offset);
  106. mutex_unlock(&data->lock);
  107. return retval;
  108. }
  109. static ssize_t cps226_eeprom_write(
  110. struct i2c_client *client,
  111. struct cps226_data *data,
  112. char *buf, unsigned offset, size_t count)
  113. {
  114. struct i2c_msg msg[1];
  115. u8 *msgbuf;
  116. unsigned long timeout, transfer_time;
  117. int status;
  118. memset(msg, 0, sizeof(msg));
  119. msgbuf = data->data;
  120. // msgbuf[0] = (u8)((offset >> 18) & 0x3f);
  121. // msgbuf[1] = (u8)((offset >> 10) & 0xff);
  122. // msgbuf[2] = (u8)((offset >> 2) & 0xff);
  123. msgbuf[0] = (u8)(offset & 0xff);
  124. memcpy(msgbuf+1, buf, count);
  125. msg[0].addr = client->addr;
  126. msg[0].buf = msgbuf;
  127. msg[0].len = 1 + count;
  128. /*
  129. * Reads fail if the previous write didn't complete yet. We may
  130. * loop a few times until this one succeeds, waiting at least
  131. * long enough for one entire page write to work.
  132. */
  133. timeout = jiffies + msecs_to_jiffies(write_timeout);
  134. do {
  135. transfer_time = jiffies;
  136. status = i2c_transfer(client->adapter, msg, 1);
  137. if (status == 1)
  138. status = count;
  139. dev_dbg(&client->dev, "write %ld@0x%lx --> %d (%ld)\n",
  140. count, (unsigned long)offset, status, jiffies);
  141. if (status == count)
  142. return count;
  143. /* REVISIT: at HZ=100, this is sloooow */
  144. msleep(1);
  145. } while (time_before(transfer_time, timeout));
  146. return -ETIMEDOUT;
  147. }
  148. static ssize_t cps226_write(struct file *filp, struct kobject *kobj,
  149. struct bin_attribute *bin_attr,
  150. char *buf, loff_t offset, size_t count)
  151. {
  152. struct i2c_client *client = kobj_to_i2c_client(kobj);
  153. struct cps226_data *data = i2c_get_clientdata(client);
  154. ssize_t retval = 0;
  155. if (offset > USER_EEPROM_SIZE)
  156. return 0;
  157. if (offset + count > USER_EEPROM_SIZE)
  158. count = USER_EEPROM_SIZE - offset;
  159. mutex_lock(&data->lock);
  160. dev_dbg(&client->dev, "cps226 start write %ld@0x%lx ..\n", count, (unsigned long)offset);
  161. while (count > 0) {
  162. ssize_t status = count>USER_XFER_MAX_COUNT?USER_XFER_MAX_COUNT:count;
  163. status = cps226_eeprom_write(client, data, buf, offset, status);
  164. if (status <= 0) {
  165. if (retval == 0)
  166. retval = status;
  167. break;
  168. }
  169. buf += status;
  170. offset += status;
  171. count -= status;
  172. retval += status;
  173. }
  174. dev_dbg(&client->dev, "cps226 end write %ld@0x%lx !\n", retval, (unsigned long)offset);
  175. mutex_unlock(&data->lock);
  176. return retval;
  177. }
  178. static struct bin_attribute user_eeprom_attr = {
  179. .attr = {
  180. .name = "eeprom",
  181. .mode = (S_IRUSR | S_IWUSR),
  182. },
  183. .size = USER_EEPROM_SIZE,
  184. .read = cps226_read,
  185. .write = cps226_write,
  186. };
  187. /* Return 0 if detection is successful, -ENODEV otherwise */
  188. static int cps226_detect(struct i2c_client *client, struct i2c_board_info *info)
  189. {
  190. struct i2c_adapter *adapter = client->adapter;
  191. if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
  192. dev_dbg(&client->dev, "cps226 detect error for BYTE access !\n");
  193. return -ENODEV;
  194. }
  195. strlcpy(info->type, "eeprom", I2C_NAME_SIZE);
  196. return 0;
  197. }
  198. static int cps226_probe(struct i2c_client *client,
  199. const struct i2c_device_id *id)
  200. {
  201. struct i2c_adapter *adapter = client->adapter;
  202. struct cps226_data *data;
  203. int err ;
  204. dev_notice(&client->dev, "cps226 driver\n" );
  205. if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
  206. dev_err(&client->dev, "cps226 driver: BYTE DATA not supported! \n" );
  207. return -ENODEV;
  208. }
  209. if (!(data = kzalloc(sizeof(struct cps226_data), GFP_KERNEL))) {
  210. dev_err(&client->dev, "cps226 driver: Memory alloc error ! \n" );
  211. return -ENOMEM;
  212. }
  213. /* alloc buffer */
  214. data->data = devm_kzalloc(&client->dev, USER_XFER_MAX_COUNT + 8, GFP_KERNEL);
  215. if (!data->data) {
  216. dev_err(&client->dev, "cps226 driver: Memory alloc error ! \n" );
  217. err = -ENOMEM;
  218. goto exit_kfree;
  219. }
  220. /* Init real i2c_client */
  221. i2c_set_clientdata(client, data);
  222. mutex_init(&data->lock);
  223. err = sysfs_create_bin_file(&client->dev.kobj, &user_eeprom_attr);
  224. if (err) {
  225. dev_err(&client->dev, "cps226 driver: sysfs create error ! \n" );
  226. goto exit_kfree;
  227. }
  228. return 0;
  229. exit_kfree:
  230. if(data->data)
  231. kfree(data->data);
  232. kfree(data);
  233. return err;
  234. }
  235. static int cps226_remove(struct i2c_client *client)
  236. {
  237. struct cps226_data *data = i2c_get_clientdata(client);
  238. sysfs_remove_bin_file(&client->dev.kobj, &user_eeprom_attr);
  239. if(data->data)
  240. kfree(data->data);
  241. kfree(data);
  242. return 0;
  243. }
  244. static const struct i2c_device_id cps226_id[] = {
  245. { "cps226", 0 },
  246. { }
  247. };
  248. MODULE_DEVICE_TABLE(i2c, cps226_id);
  249. static struct i2c_driver cps226_driver = {
  250. .driver = {
  251. .name = "cps226",
  252. },
  253. .probe = cps226_probe,
  254. .remove = cps226_remove,
  255. .id_table = cps226_id,
  256. .class = I2C_CLASS_SPD,
  257. .detect = cps226_detect,
  258. .address_list = cps226_i2c,
  259. };
  260. module_i2c_driver(cps226_driver);
  261. MODULE_AUTHOR("RobinLee");
  262. MODULE_DESCRIPTION("cps226 driver");
  263. MODULE_LICENSE("GPL");

4、devicetree配置

devicetree中需要配置四个从设备的地址,如下,dbf名称懒得改了:

  1. /dts-v1/;
  2. / {
  3. #address-cells = <0x1>;
  4. #size-cells = <0x1>;
  5. compatible = "xlnx,zynq-7000";
  6. cpus {
  7. #address-cells = <0x1>;
  8. #size-cells = <0x0>;
  9. cpu@0 {
  10. compatible = "arm,cortex-a9";
  11. device_type = "cpu";
  12. reg = <0x0>;
  13. clocks = <0x1 0x3>;
  14. clock-latency = <0x3e8>;
  15. cpu0-supply = <0x2>;
  16. operating-points = <0xa4cb8 0xf4240 0x5265c 0xf4240>;
  17. };
  18. cpu@1 {
  19. compatible = "arm,cortex-a9";
  20. device_type = "cpu";
  21. reg = <0x1>;
  22. clocks = <0x1 0x3>;
  23. };
  24. };
  25. fpga-full {
  26. compatible = "fpga-region";
  27. fpga-mgr = <0x3>;
  28. #address-cells = <0x1>;
  29. #size-cells = <0x1>;
  30. ranges;
  31. };
  32. pmu@f8891000 {
  33. compatible = "arm,cortex-a9-pmu";
  34. interrupts = <0x0 0x5 0x4 0x0 0x6 0x4>;
  35. interrupt-parent = <0x4>;
  36. reg = <0xf8891000 0x1000 0xf8893000 0x1000>;
  37. };
  38. fixedregulator {
  39. compatible = "regulator-fixed";
  40. regulator-name = "VCCPINT";
  41. regulator-min-microvolt = <0xf4240>;
  42. regulator-max-microvolt = <0xf4240>;
  43. regulator-boot-on;
  44. regulator-always-on;
  45. linux,phandle = <0x2>;
  46. phandle = <0x2>;
  47. };
  48. amba {
  49. u-boot,dm-pre-reloc;
  50. compatible = "simple-bus";
  51. #address-cells = <0x1>;
  52. #size-cells = <0x1>;
  53. interrupt-parent = <0x4>;
  54. ranges;
  55. adc@f8007100 {
  56. compatible = "xlnx,zynq-xadc-1.00.a";
  57. reg = <0xf8007100 0x20>;
  58. interrupts = <0x0 0x7 0x4>;
  59. interrupt-parent = <0x4>;
  60. clocks = <0x1 0xc>;
  61. xlnx,channels {
  62. #address-cells = <1>;
  63. #size-cells = <0>;
  64. channel@0 {
  65. reg = <0>;
  66. };
  67. channel@1 {
  68. reg = <1>;
  69. };
  70. channel@2 {
  71. reg = <2>;
  72. };
  73. channel@3 {
  74. reg = <3>;
  75. };
  76. channel@4{
  77. reg = <4>;
  78. };
  79. channel@5{
  80. reg = <5>;
  81. };
  82. channel@6{
  83. reg = <6>;
  84. };
  85. channel@7{
  86. reg = <7>;
  87. };
  88. channel@8 {
  89. reg = <8>;
  90. };
  91. channel@9 {
  92. reg = <9>;
  93. };
  94. channel@a {
  95. reg = <0xa>;
  96. };
  97. channel@b {
  98. reg = <0xb>;
  99. };
  100. channel@c {
  101. reg = <0xc>;
  102. };
  103. channel@d {
  104. reg = <0xd>;
  105. };
  106. channel@e {
  107. reg = <0xe>;
  108. };
  109. channel@f {
  110. reg = <0xf>;
  111. };
  112. channel@10 {
  113. reg = <0x10>;
  114. };
  115. };
  116. };
  117. gpio@e000a000 {
  118. compatible = "xlnx,zynq-gpio-1.0";
  119. #gpio-cells = <0x2>;
  120. clocks = <0x1 0x2a>;
  121. gpio-controller;
  122. interrupt-controller;
  123. #interrupt-cells = <0x2>;
  124. interrupt-parent = <0x4>;
  125. interrupts = <0x0 0x14 0x4>;
  126. reg = <0xe000a000 0x1000>;
  127. };
  128. i2c@e0004000 {
  129. compatible = "cdns,i2c-r1p10";
  130. status = "okay";
  131. clocks = <0x1 0x26>;
  132. interrupt-parent = <0x4>;
  133. interrupts = <0x0 0x19 0x4>;
  134. reg = <0xe0004000 0x1000>;
  135. #address-cells = <0x1>;
  136. #size-cells = <0x0>;
  137. clock-frequency = <0x61a80>;
  138. cps1848@2 {
  139. compatible = "cps1848";
  140. reg = <0x2>;
  141. };
  142. cps1848@4 {
  143. compatible = "cps1848";
  144. reg = <0x4>;
  145. };
  146. cps1848@8 {
  147. compatible = "cps1848";
  148. reg = <0x8>;
  149. };
  150. cps226@40 {
  151. compatible = "cps226";
  152. reg = <0x40>;
  153. };
  154. };
  155. i2c@e0005000 {
  156. compatible = "cdns,i2c-r1p10";
  157. status = "okay";
  158. clocks = <0x1 0x27>;
  159. interrupt-parent = <0x4>;
  160. interrupts = <0x0 0x30 0x4>;
  161. reg = <0xe0005000 0x1000>;
  162. #address-cells = <0x1>;
  163. #size-cells = <0x0>;
  164. clock-frequency = <0x61a80>;
  165. };
  166. interrupt-controller@f8f01000 {
  167. compatible = "arm,cortex-a9-gic";
  168. #interrupt-cells = <0x3>;
  169. interrupt-controller;
  170. reg = <0xf8f01000 0x1000 0xf8f00100 0x100>;
  171. num_cpus = <0x2>;
  172. num_interrupts = <0x60>;
  173. linux,phandle = <0x4>;
  174. phandle = <0x4>;
  175. };
  176. cache-controller@f8f02000 {
  177. compatible = "arm,pl310-cache";
  178. reg = <0xf8f02000 0x1000>;
  179. interrupts = <0x0 0x2 0x4>;
  180. arm,data-latency = <0x3 0x2 0x2>;
  181. arm,tag-latency = <0x2 0x2 0x2>;
  182. cache-unified;
  183. cache-level = <0x2>;
  184. };
  185. memory-controller@f8006000 {
  186. compatible = "xlnx,zynq-ddrc-a05";
  187. reg = <0xf8006000 0x1000>;
  188. };
  189. ocmc@f800c000 {
  190. compatible = "xlnx,zynq-ocmc-1.0";
  191. interrupt-parent = <0x4>;
  192. interrupts = <0x0 0x3 0x4>;
  193. reg = <0xf800c000 0x1000>;
  194. };
  195. serial@e0000000 {
  196. compatible = "xlnx,xuartps", "cdns,uart-r1p8";
  197. status = "okay";
  198. clocks = <0x1 0x17 0x1 0x28>;
  199. clock-names = "uart_clk", "pclk";
  200. reg = <0xe0000000 0x1000>;
  201. interrupts = <0x0 0x1b 0x4>;
  202. device_type = "serial";
  203. port-number = <0x0>;
  204. };
  205. spi@e0006000 {
  206. compatible = "xlnx,zynq-spi-r1p6";
  207. reg = <0xe0006000 0x1000>;
  208. status = "okay";
  209. interrupt-parent = <0x4>;
  210. interrupts = <0x0 0x1a 0x4>;
  211. clocks = <0x1 0x19 0x1 0x22>;
  212. clock-names = "ref_clk", "pclk";
  213. #address-cells = <0x1>;
  214. #size-cells = <0x0>;
  215. is-decoded-cs = <0x0>;
  216. num-cs = <0x3>;
  217. };
  218. spi@e0007000 {
  219. compatible = "xlnx,zynq-spi-r1p6";
  220. reg = <0xe0007000 0x1000>;
  221. status = "okay";
  222. interrupt-parent = <0x4>;
  223. interrupts = <0x0 0x31 0x4>;
  224. clocks = <0x1 0x1a 0x1 0x23>;
  225. clock-names = "ref_clk", "pclk";
  226. #address-cells = <0x1>;
  227. #size-cells = <0x0>;
  228. is-decoded-cs = <0x0>;
  229. num-cs = <0x3>;
  230. flash@0 {
  231. compatible = "micron,n25q128a11","jedec,spi-nor";
  232. reg = <0x1>;
  233. spi-max-frequency = <0x9EF21B0>;
  234. spi-tx-bus-width = <0x1>;
  235. spi-rx-bus-width = <0x1>;
  236. #address-cells = <0x1>;
  237. #size-cells = <0x1>;
  238. partition@dbf {
  239. label = "spi-flash";
  240. reg = <0x0 0x1000000>;
  241. };
  242. };
  243. };
  244. spi@e000d000 {
  245. clock-names = "ref_clk", "pclk";
  246. clocks = <0x1 0xa 0x1 0x2b>;
  247. compatible = "xlnx,zynq-qspi-1.0";
  248. status = "okay";
  249. interrupt-parent = <0x4>;
  250. interrupts = <0x0 0x13 0x4>;
  251. reg = <0xe000d000 0x1000>;
  252. #address-cells = <0x1>;
  253. #size-cells = <0x0>;
  254. is-dual = <0x1>;
  255. num-cs = <0x1>;
  256. };
  257. ethernet@e000b000 {
  258. compatible = "xlnx,ps7-ethernet-1.00.a";
  259. reg = <0xe000b000 0x1000>;
  260. status = "okay";
  261. interrupt-parent = <0x3>;
  262. interrupts = <0x0 0x16 0x4>;
  263. clocks = <0x1 0xd 0x1 0x1e>;
  264. clock-names = "ref_clk", "aper_clk";
  265. #address-cells = <0x1>;
  266. #size-cells = <0x0>;
  267. enet-reset = <0x4 0x2f 0x0>;
  268. local-mac-address = [00 0a 35 00 00 00];
  269. phy-mode = "rgmii";
  270. phy-handle = <0x5>;
  271. xlnx,eth-mode = <0x1>;
  272. xlnx,has-mdio = <0x1>;
  273. xlnx,ptp-enet-clock = <0x69f6bcb>;
  274. mdio {
  275. #address-cells = <0x1>;
  276. #size-cells = <0x0>;
  277. phy@0 {
  278. compatible = "marvell,88e1111";
  279. device_type = "ethernet-phy";
  280. reg = <0x4>;
  281. linux,phandle = <0x7>;
  282. phandle = <0x7>;
  283. };
  284. };
  285. };
  286. slcr@f8000000 {
  287. #address-cells = <0x1>;
  288. #size-cells = <0x1>;
  289. compatible = "xlnx,zynq-slcr", "syscon", "simple-mfd";
  290. reg = <0xf8000000 0x1000>;
  291. ranges;
  292. linux,phandle = <0x5>;
  293. phandle = <0x5>;
  294. clkc@100 {
  295. #clock-cells = <0x1>;
  296. compatible = "xlnx,ps7-clkc";
  297. fclk-enable = <0x1>;
  298. 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";
  299. reg = <0x100 0x100>;
  300. ps-clk-frequency = <0x2faf080>;
  301. linux,phandle = <0x1>;
  302. phandle = <0x1>;
  303. };
  304. rstc@200 {
  305. compatible = "xlnx,zynq-reset";
  306. reg = <0x200 0x48>;
  307. #reset-cells = <0x1>;
  308. syscon = <0x5>;
  309. };
  310. pinctrl@700 {
  311. compatible = "xlnx,pinctrl-zynq";
  312. reg = <0x700 0x200>;
  313. syscon = <0x5>;
  314. };
  315. };
  316. dmac@f8003000 {
  317. compatible = "arm,pl330", "arm,primecell";
  318. reg = <0xf8003000 0x1000>;
  319. interrupt-parent = <0x4>;
  320. interrupt-names = "abort", "dma0", "dma1", "dma2", "dma3", "dma4", "dma5", "dma6", "dma7";
  321. 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>;
  322. #dma-cells = <0x1>;
  323. #dma-channels = <0x8>;
  324. #dma-requests = <0x4>;
  325. clocks = <0x1 0x1b>;
  326. clock-names = "apb_pclk";
  327. };
  328. devcfg@f8007000 {
  329. compatible = "xlnx,zynq-devcfg-1.0";
  330. interrupt-parent = <0x4>;
  331. interrupts = <0x0 0x8 0x4>;
  332. reg = <0xf8007000 0x100>;
  333. clocks = <0x1 0xc 0x1 0xf 0x1 0x10 0x1 0x11 0x1 0x12>;
  334. clock-names = "ref_clk", "fclk0", "fclk1", "fclk2", "fclk3";
  335. syscon = <0x5>;
  336. linux,phandle = <0x3>;
  337. phandle = <0x3>;
  338. };
  339. efuse@f800d000 {
  340. compatible = "xlnx,zynq-efuse";
  341. reg = <0xf800d000 0x20>;
  342. };
  343. timer@f8f00200 {
  344. compatible = "arm,cortex-a9-global-timer";
  345. reg = <0xf8f00200 0x20>;
  346. interrupts = <0x1 0xb 0x301>;
  347. interrupt-parent = <0x4>;
  348. clocks = <0x1 0x4>;
  349. };
  350. timer@f8001000 {
  351. interrupt-parent = <0x4>;
  352. interrupts = <0x0 0xa 0x4 0x0 0xb 0x4 0x0 0xc 0x4>;
  353. compatible = "cdns,ttc";
  354. clocks = <0x1 0x6>;
  355. reg = <0xf8001000 0x1000>;
  356. };
  357. timer@f8002000 {
  358. interrupt-parent = <0x4>;
  359. interrupts = <0x0 0x25 0x4 0x0 0x26 0x4 0x0 0x27 0x4>;
  360. compatible = "cdns,ttc";
  361. clocks = <0x1 0x6>;
  362. reg = <0xf8002000 0x1000>;
  363. };
  364. timer@f8f00600 {
  365. interrupt-parent = <0x4>;
  366. interrupts = <0x1 0xd 0x301>;
  367. compatible = "arm,cortex-a9-twd-timer";
  368. reg = <0xf8f00600 0x20>;
  369. clocks = <0x1 0x4>;
  370. };
  371. watchdog@f8005000 {
  372. clocks = <0x1 0x2d>;
  373. compatible = "cdns,wdt-r1p2";
  374. interrupt-parent = <0x4>;
  375. interrupts = <0x0 0x9 0x1>;
  376. reg = <0xf8005000 0x1000>;
  377. timeout-sec = <0xa>;
  378. };
  379. };
  380. chosen {
  381. bootargs = "earlycon";
  382. stdout-path = "serial0:115200n8";
  383. };
  384. aliases {
  385. ethernet0 = "/amba/ethernet@e000b000";
  386. serial0 = "/amba/serial@e0000000";
  387. spi0 = "/amba/spi@e000d000";
  388. spi1 = "/amba/spi@e0006000";
  389. spi2 = "/amba/spi@e0007000";
  390. };
  391. memory {
  392. device_type = "memory";
  393. reg = <0x0 0x40000000>;
  394. };
  395. };

 

5、应用示例

应用可以参考1848那样提供读写寄存器接口函数,这里要注意数据高低位转换问题,是否需要使用htonl函数,不同的芯片要求不一样。

DBF芯片代码如下:

  1. /*
  2. * cps1848.h
  3. *
  4. * Created on: 2018年9月8日
  5. * Author: Administrator
  6. */
  7. #ifndef SRC_CPS1848_H_
  8. #define SRC_CPS1848_H_
  9. int Init_1848();
  10. unsigned int get_1848_reg(int num,unsigned int offset);
  11. void set_1848_reg(int num,unsigned int offset, unsigned int data);
  12. #endif /* SRC_CPS1848_H_ */
  1. /*
  2. * Copyright (c) 2016 CGT Co., Ltd.
  3. *
  4. * Authors: Robin Lee <lixiangbin@china-dsp.com>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program;
  18. *
  19. */
  20. #include <stdio.h>
  21. #include <stdlib.h>
  22. #include <stdarg.h>
  23. #include <string.h>
  24. #include <memory.h>
  25. #include <sys/types.h>
  26. #include <sys/stat.h>
  27. #include <sys/ioctl.h>
  28. #include <sys/poll.h>
  29. #include <sys/time.h>
  30. #include <sys/socket.h>
  31. #include <fcntl.h>
  32. #include <errno.h>
  33. #include <pthread.h>
  34. #include <math.h>
  35. #include <unistd.h>
  36. #include <signal.h>
  37. #include <termios.h>
  38. #include <netinet/in.h>
  39. #include "cps1848.h"
  40. /*---------------------------------------------------------------------------------------------------------------------------------------------------
  41. * global vars
  42. */
  43. #define FP_DEV_1 "/sys/class/i2c-dev/i2c-0/device/0-0002/eeprom"
  44. #define FP_DEV_2 "/sys/class/i2c-dev/i2c-0/device/0-0004/eeprom"
  45. #define FP_DEV_3 "/sys/class/i2c-dev/i2c-0/device/0-0008/eeprom"
  46. static int global_fd_1 = -1;
  47. static int global_fd_2 = -1;
  48. static int global_fd_3 = -1;
  49. //operations of cps1848
  50. int fd_initial(int num)
  51. {
  52. int fd = -1;
  53. /*
  54. Open modem device for reading and writing and not as controlling tty
  55. because we don't want to get killed if linenoise sends CTRL-C.
  56. */
  57. if(num==0)
  58. {
  59. printf("Open '%s' .. ", FP_DEV_1);
  60. fd = open(FP_DEV_1, O_RDWR );
  61. }
  62. else if(num==1)
  63. {
  64. printf("Open '%s' .. ", FP_DEV_2);
  65. fd = open(FP_DEV_2, O_RDWR );
  66. }
  67. else if(num==2)
  68. {
  69. printf("Open '%s' .. ", FP_DEV_3);
  70. fd = open(FP_DEV_3, O_RDWR );
  71. }
  72. else
  73. {
  74. printf("Open error.\n");
  75. return -1;
  76. }
  77. if (fd <0) {
  78. printf("failed (err = %d)\n", fd);
  79. return -1;
  80. }
  81. printf("Done\n");
  82. return fd;
  83. }
  84. int fd_exit(int fd,int num)
  85. {
  86. if(num==1)
  87. {
  88. printf("Close '%s' .. ", FP_DEV_1);
  89. }
  90. else if(num==2)
  91. {
  92. printf("Close '%s' .. ", FP_DEV_2);
  93. }
  94. else
  95. {
  96. printf("Close '%s' .. ", FP_DEV_3);
  97. }
  98. close(fd);
  99. printf("Done\n");
  100. return 0;
  101. }
  102. /*---------------------------------------------------------------------------------------------------------------------------------------------------
  103. * get_1848_reg, set_1848_reg
  104. */
  105. unsigned int get_1848_reg(int num,unsigned int offset)
  106. {
  107. unsigned int value = 0xffff;
  108. unsigned int ans=0;
  109. int fd=-1;
  110. if(num==0)
  111. {
  112. fd=global_fd_1;
  113. }
  114. else if(num==1)
  115. {
  116. fd=global_fd_2;
  117. }
  118. else if( num==2 )
  119. {
  120. fd=global_fd_3;
  121. }
  122. else
  123. {
  124. printf("get_dbf_reg::Invalid param !\n");
  125. return 0;
  126. }
  127. if (fd<0) {
  128. printf("Invalid device handle !\n");
  129. return value;
  130. }
  131. if( lseek(fd, offset, SEEK_SET) == (off_t) -1 ) {
  132. printf("failed for seek to offset 0x%x !\n", offset);
  133. return value;
  134. }
  135. if ( read(fd, &value, sizeof(value)) != sizeof(value)) {
  136. printf("failed for read from offset 0x%x !\n", offset);
  137. return value;
  138. }
  139. //ans=htonl(value);
  140. return value;
  141. }
  142. void set_1848_reg(int num,unsigned int offset, unsigned int data)
  143. {
  144. unsigned int value = data;
  145. int fd=-1;
  146. if(num==0)
  147. {
  148. fd=global_fd_1;
  149. }
  150. else if(num==1)
  151. {
  152. fd=global_fd_2;
  153. }
  154. else if( num==2 )
  155. {
  156. fd=global_fd_3;
  157. }
  158. else
  159. {
  160. printf("set_dbf_reg::Invalid param !\n");
  161. return;
  162. }
  163. if (fd<0) {
  164. printf("Invalid device handle !\n");
  165. return ;
  166. }
  167. if( lseek(fd, offset, SEEK_SET) == (off_t) -1 ) {
  168. printf("failed for seek to offset 0x%x !\n", offset);
  169. return ;
  170. }
  171. if ( write(fd, &value, sizeof(value)) != sizeof(value)) {
  172. // printf("failed for write from offset 0x%x !\n", offset);
  173. return ;
  174. }
  175. return ;
  176. }
  177. unsigned int regtoul(const char *str)
  178. {
  179. int cbase = 10;
  180. if(str[0]=='0'&&(str[1]=='x'||str[1]=='X')) {
  181. cbase = 16;
  182. }
  183. return strtoul(str, NULL, cbase);
  184. }
  185. int Init_1848()
  186. {
  187. global_fd_1 = fd_initial(0);
  188. global_fd_2 = fd_initial(1);
  189. global_fd_3 = fd_initial(2);
  190. if (global_fd_1<0) {
  191. printf("\n Invalid First dbf device ! \n");
  192. return -1;
  193. }
  194. if (global_fd_2<0) {
  195. printf("\n Invalid Second dbf device ! \n");
  196. return -1;
  197. }
  198. if (global_fd_3<0) {
  199. printf("\n Invalid Third dbf device ! \n");
  200. return -1;
  201. }
  202. return 0;
  203. }

Ti 226芯片读写接口如下

  1. /*
  2. * cps1848.h
  3. *
  4. * Created on: 2018年9月8日
  5. * Author: Administrator
  6. */
  7. #ifndef SRC_CPS226_H_
  8. #define SRC_CPS226_H_
  9. int Init_226();
  10. unsigned int get_226_reg(unsigned int offset);
  11. void set_226_reg(unsigned int offset, unsigned int data);
  12. #endif /* SRC_CPS1848_H_ */
  1. /*
  2. * Copyright (c) 2016 CGT Co., Ltd.
  3. *
  4. * Authors: Robin Lee <lixiangbin@china-dsp.com>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program;
  18. *
  19. */
  20. #include <stdio.h>
  21. #include <stdlib.h>
  22. #include <stdarg.h>
  23. #include <string.h>
  24. #include <memory.h>
  25. #include <sys/types.h>
  26. #include <sys/stat.h>
  27. #include <sys/ioctl.h>
  28. #include <sys/poll.h>
  29. #include <sys/time.h>
  30. #include <sys/socket.h>
  31. #include <fcntl.h>
  32. #include <errno.h>
  33. #include <pthread.h>
  34. #include <math.h>
  35. #include <unistd.h>
  36. #include <signal.h>
  37. #include <termios.h>
  38. #include <netinet/in.h>
  39. #include "cps226.h"
  40. /*---------------------------------------------------------------------------------------------------------------------------------------------------
  41. * global vars
  42. */
  43. #define FP_DEV "/sys/class/i2c-dev/i2c-0/device/0-0040/eeprom"
  44. static int global_fd = -1;
  45. //operations of cps1848
  46. int fd_initial_226()
  47. {
  48. int fd = -1;
  49. /*
  50. Open modem device for reading and writing and not as controlling tty
  51. because we don't want to get killed if linenoise sends CTRL-C.
  52. */
  53. printf("Open '%s' .. ", FP_DEV);
  54. fd = open(FP_DEV, O_RDWR );
  55. if (fd <0) {
  56. printf("failed (err = %d)\n", fd);
  57. return -1;
  58. }
  59. printf("Done\n");
  60. return fd;
  61. }
  62. int fd_exit_226(int fd)
  63. {
  64. close(fd);
  65. printf("Done\n");
  66. return 0;
  67. }
  68. /*---------------------------------------------------------------------------------------------------------------------------------------------------
  69. * get_1848_reg, set_1848_reg
  70. */
  71. unsigned int get_226_reg(unsigned int offset)
  72. {
  73. unsigned int value = 0xffff;
  74. unsigned int ans=0;
  75. int fd=-1;
  76. fd=global_fd;
  77. if (fd<0) {
  78. printf("Invalid device handle !\n");
  79. return value;
  80. }
  81. if( lseek(fd, offset, SEEK_SET) == (off_t) -1 ) {
  82. printf("failed for seek to offset 0x%x !\n", offset);
  83. return value;
  84. }
  85. if ( read(fd, &value, sizeof(value)) != sizeof(value)) {
  86. printf("failed for read from offset 0x%x !\n", offset);
  87. return value;
  88. }
  89. ans=htonl(value);
  90. return ans>>16;
  91. }
  92. void set_226_reg(unsigned int offset, unsigned int data)
  93. {
  94. unsigned int value = data;
  95. int fd=-1;
  96. fd=global_fd;
  97. if (fd<0) {
  98. printf("Invalid device handle !\n");
  99. return ;
  100. }
  101. if( lseek(fd, offset, SEEK_SET) == (off_t) -1 ) {
  102. printf("failed for seek to offset 0x%x !\n", offset);
  103. return ;
  104. }
  105. if ( write(fd, &value, sizeof(value)) != sizeof(value)) {
  106. // printf("failed for write from offset 0x%x !\n", offset);
  107. return ;
  108. }
  109. return ;
  110. }
  111. unsigned int regtoul_226(const char *str)
  112. {
  113. int cbase = 10;
  114. if(str[0]=='0'&&(str[1]=='x'||str[1]=='X')) {
  115. cbase = 16;
  116. }
  117. return strtoul(str, NULL, cbase);
  118. }
  119. int Init_226()
  120. {
  121. global_fd = fd_initial_226();
  122. if (global_fd<0)
  123. {
  124. printf("\n Invalid 226 device ! \n");
  125. return -1;
  126. }
  127. return 0;
  128. }

 

6、测试说明

Linux启动过程中能看到驱动正确加载,显然设备都找到了。

启动应用后能读出DBF芯片原来的ID,并根据槽位号配置新的ID

代码如下:

  1. /*
  2. * config_dbf.c
  3. *
  4. * Created on: 2018年8月17日
  5. * Author: Administrator
  6. */
  7. #include "config_dbf.h"
  8. #include "gpio.h"
  9. #include "cps1848.h"
  10. extern unsigned int ga_chass;
  11. int config_dbf_id()
  12. {
  13. unsigned int _data;
  14. u32 chip_id;
  15. printf("Change dbf id start\n");
  16. printf("------------Set DBFA ID Register------------\n");
  17. _data=get_1848_reg(0,0);
  18. printf("orignial DBFA ID = 0x%x\n",_data);
  19. chip_id = (ga_chass<<4) | 0x1;
  20. set_1848_reg(0,0,chip_id);
  21. _data=get_1848_reg(0,0);
  22. printf("config DBFA ID = 0x%x\n",_data);
  23. printf("------------Set DBFB ID Register------------\n");
  24. _data=get_1848_reg(1,0);
  25. printf("orignial DBFB ID = 0x%x\n",_data);
  26. chip_id = (ga_chass<<4) | 0x2;
  27. set_1848_reg(1,0,chip_id);
  28. _data=get_1848_reg(1,0);
  29. printf("config DBFB ID = 0x%x\n",_data);
  30. printf("------------Set DBFC ID Register------------\n");
  31. _data=get_1848_reg(2,0);
  32. printf("orignial DBFC ID = 0x%x\n",_data);
  33. chip_id = (ga_chass<<4) | 0x3;
  34. set_1848_reg(2,0,chip_id);
  35. _data=get_1848_reg(2,0);
  36. printf("config DBFC ID = 0x%x\n",_data);
  37. return 0;
  38. }
  39. int read_dbf_id()
  40. {
  41. unsigned int _data;
  42. _data=get_1848_reg(0,0);
  43. printf("DBFA ID = 0x%x\n",_data);//true data is 1002
  44. _data=get_1848_reg(1,0);
  45. printf("DBFB ID = 0x%x\n",_data);//true data is 1003
  46. _data=get_1848_reg(2,0);
  47. printf("DBFC ID = 0x%x\n",_data);//true data is 1004
  48. return 0;
  49. }
  50. int change_dbf_uart(int id)
  51. {
  52. if(id==0)
  53. {
  54. SetGpioReg(GPIO_UAET_SELECT_BASE_ADDR,0x0,0);
  55. }
  56. else if(id==1)
  57. {
  58. SetGpioReg(GPIO_UAET_SELECT_BASE_ADDR,0x0,1);
  59. }
  60. else
  61. {
  62. SetGpioReg(GPIO_UAET_SELECT_BASE_ADDR,0x0,2);
  63. }
  64. return 0;
  65. }
  66. #if 0
  67. int bit_226()
  68. {
  69. unsigned int val32;
  70. unsigned short val16;
  71. unsigned int _data;
  72. float TempData;
  73. int Status;
  74. int ret=0;
  75. ret=IICRead_Reg(IIC_SLAVE_ADDR_226,0x05,&_data);
  76. if(ret<0)
  77. {
  78. goto error;
  79. }
  80. ret=IICWrite_Reg(IIC_SLAVE_ADDR_226,0x05,0x1400);
  81. if(ret<0)
  82. {
  83. goto error;
  84. }
  85. ret=IICRead_Reg(IIC_SLAVE_ADDR_226,0x05,&_data);
  86. if(ret<0)
  87. {
  88. goto error;
  89. }
  90. ret=IICWrite_Reg(IIC_SLAVE_ADDR_226,0x02,0x1400);
  91. if(ret<0)
  92. {
  93. goto error;
  94. }
  95. ret=IICRead_Reg(IIC_SLAVE_ADDR_226,0x05,&_data);
  96. if(ret<0)
  97. {
  98. goto error;
  99. }
  100. val32=_data;
  101. val16=(val32)&0xFFFF;
  102. ret=IICRead_Reg(IIC_SLAVE_ADDR_226,0x02,&_data);
  103. if(ret<0)
  104. {
  105. goto error;
  106. }
  107. val32=_data;
  108. val16=(val32)&0xFFFF;
  109. TempData = val16*1.0/1000.0;
  110. printf("bus voltage is %f V.\n", TempData);
  111. ret=IICRead_Reg(IIC_SLAVE_ADDR_226,0x04,&_data);
  112. if(ret<0)
  113. {
  114. goto error;
  115. }
  116. val32=_data;
  117. val16=(val32)&0xFFFF;
  118. TempData = val16*1.0/1000.0;
  119. printf("bus current is %f A.\n", TempData);
  120. if(TempData>=15.0)
  121. {
  122. printf("-----safe_rst because of Current----\n");
  123. SetGpioReg(GPIO_DBF_RESET_ADDR,0x0,1);
  124. SetGpioReg(GPIO_DBF_RESET_ADDR,0x0,0);
  125. }
  126. ret=IICRead_Reg(IIC_SLAVE_ADDR_226,0x03,&_data);
  127. if(ret<0)
  128. {
  129. goto error;
  130. }
  131. val32=_data;
  132. val16=(val32)&0xFFFF;
  133. TempData = val16*25.0/1000.0;
  134. printf("power is %f W.\n", TempData);
  135. return 0;
  136. error:
  137. return -1;
  138. }
  139. #endif

Ti 226芯片也能读出功耗了

读功耗代码如下:

  1. #include <stdio.h>
  2. #include "bit.h"
  3. #include "config_dbf.h"
  4. #include "gpio.h"
  5. #include "cps226.h"
  6. extern unsigned int g_temp[10];
  7. extern unsigned int g_vcc[9];
  8. extern unsigned int g_vcc_aux[16];
  9. void Show_226_bit()
  10. {
  11. unsigned int _data,val32;
  12. unsigned short val16;
  13. float temp;
  14. _data=get_226_reg(0x05);
  15. set_226_reg(0x05,0x14);
  16. _data=get_226_reg(0x05);
  17. set_226_reg(0x02,0x14);
  18. val32=get_226_reg(0x05);
  19. val16=val32&0xffff;
  20. val32 = get_226_reg(0x02);
  21. val16 = (val32)&0xFFFF;
  22. temp = val16*1.25/1000.0;
  23. printf("bus voltage is %.3f V. \n",temp);
  24. val32 = get_226_reg(0x04);
  25. val16 = (val32)&0xFFFF;
  26. temp = val16*1.0/1000.0;
  27. printf("Current is %.3f A. \n", temp);
  28. if(temp>=15)
  29. {
  30. printf("Warning!!! DBF Current Amp Alarm! Reset DBF NOW!!!\n");
  31. SetGpioReg(GPIO_DBF_RESET_ADDR,0,0x1);
  32. SetGpioReg(GPIO_DBF_RESET_ADDR,0,0x0);
  33. }
  34. val32 = get_226_reg(0x03);
  35. val16 = (val32)&0xFFFF ;
  36. temp = val16*25.0/1000.0;
  37. printf("Power is %.3f W. \r\n", temp);
  38. }

至此I2C驱动调试结束。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/713104
推荐阅读
相关标签
  

闽ICP备14008679号