A1-trimpot-mcp4x.c 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. /*
  2. * support for MCP46x digital trimpot used in Bitmine's products
  3. *
  4. * Copyright 2014 Zefir Kurtisi <zefir.kurtisi@gmail.com>
  5. *
  6. * This program is free software; you can redistribute it and/or modify it
  7. * under the terms of the GNU General Public License as published by the Free
  8. * Software Foundation; either version 3 of the License, or (at your option)
  9. * any later version. See COPYING for more details.
  10. */
  11. #include <assert.h>
  12. #include <errno.h>
  13. #include <string.h>
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <unistd.h>
  17. #include <linux/i2c.h>
  18. #include <linux/i2c-dev.h>
  19. #include <sys/ioctl.h>
  20. #include <stdint.h>
  21. #include <stdbool.h>
  22. #include <fcntl.h>
  23. #include "miner.h"
  24. #include "A1-trimpot-mcp4x.h"
  25. static bool mcp4x_check_status(int file)
  26. {
  27. union i2c_smbus_data data;
  28. struct i2c_smbus_ioctl_data args;
  29. args.read_write = I2C_SMBUS_READ;
  30. args.command = ((5 & 0x0f) << 4) | 0x0c;
  31. args.size = I2C_SMBUS_WORD_DATA;
  32. args.data = &data;
  33. return ioctl(file, I2C_SMBUS, &args) >= 0;
  34. }
  35. static uint16_t mcp4x_get_wiper(struct mcp4x *me, uint8_t id)
  36. {
  37. assert(id < 2);
  38. union i2c_smbus_data data;
  39. struct i2c_smbus_ioctl_data args;
  40. args.read_write = I2C_SMBUS_READ;
  41. args.command = ((id & 0x0f) << 4) | 0x0c;
  42. args.size = I2C_SMBUS_WORD_DATA;
  43. args.data = &data;
  44. if (ioctl(me->file, I2C_SMBUS, &args) < 0) {
  45. applog(LOG_ERR, "Failed to read id %d: %s\n", id,
  46. strerror(errno));
  47. return 0xffff;
  48. }
  49. return htobe16(data.word & 0xffff);
  50. }
  51. static bool mcp4x_set_wiper(struct mcp4x *me, uint8_t id, uint16_t w)
  52. {
  53. assert(id < 2);
  54. union i2c_smbus_data data;
  55. data.word = w;
  56. struct i2c_smbus_ioctl_data args;
  57. args.read_write = I2C_SMBUS_WRITE;
  58. args.command = (id & 0x0f) << 4;
  59. args.size = I2C_SMBUS_WORD_DATA;
  60. args.data = &data;
  61. if (ioctl(me->file, I2C_SMBUS, &args) < 0) {
  62. applog(LOG_ERR, "Failed to read id %d: %s\n", id,
  63. strerror(errno));
  64. return false;
  65. }
  66. return me->get_wiper(me, id) == w;
  67. }
  68. void mcp4x_exit(struct mcp4x *me)
  69. {
  70. close(me->file);
  71. free(me);
  72. }
  73. struct mcp4x *mcp4x_init(uint8_t addr)
  74. {
  75. struct mcp4x *me;
  76. int file = open("/dev/i2c-1", O_RDWR);
  77. if (file < 0) {
  78. applog(LOG_INFO, "Failed to open i2c-1: %s\n", strerror(errno));
  79. return NULL;
  80. }
  81. if (ioctl(file, I2C_SLAVE, addr) < 0)
  82. return NULL;
  83. if (!mcp4x_check_status(file))
  84. return NULL;
  85. me = malloc(sizeof(*me));
  86. assert(me != NULL);
  87. me->addr = addr;
  88. me->file = file;
  89. me->exit = mcp4x_exit;
  90. me->get_wiper = mcp4x_get_wiper;
  91. me->set_wiper = mcp4x_set_wiper;
  92. return me;
  93. }