knc-transport-spi.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. /*
  2. * Direct SPI transport layer for KnCminer Jupiters
  3. *
  4. * Copyright 2014 KnCminer
  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 <unistd.h>
  12. #include <fcntl.h>
  13. #include <sys/ioctl.h>
  14. #include <linux/spi/spidev.h>
  15. #include "logging.h"
  16. #include "miner.h"
  17. #include "hexdump.c"
  18. #include "knc-transport.h"
  19. #define SPI_DEVICE_TEMPLATE "/dev/spidev%d.%d"
  20. #define SPI_MODE (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH)
  21. #define SPI_BITS_PER_WORD 8
  22. #define SPI_MAX_SPEED 3000000
  23. #define SPI_DELAY_USECS 0
  24. struct spidev_context {
  25. int fd;
  26. uint32_t speed;
  27. uint16_t delay;
  28. uint8_t mode;
  29. uint8_t bits;
  30. };
  31. /* Init SPI transport */
  32. void *knc_trnsp_new(int dev_idx)
  33. {
  34. struct spidev_context *ctx;
  35. char dev_name[PATH_MAX];
  36. if (NULL == (ctx = malloc(sizeof(struct spidev_context)))) {
  37. applog(LOG_ERR, "KnC transport: Out of memory");
  38. goto l_exit_error;
  39. }
  40. ctx->mode = SPI_MODE;
  41. ctx->bits = SPI_BITS_PER_WORD;
  42. ctx->speed = SPI_MAX_SPEED;
  43. ctx->delay = SPI_DELAY_USECS;
  44. ctx->fd = -1;
  45. sprintf(dev_name, SPI_DEVICE_TEMPLATE,
  46. dev_idx + 1, /* bus */
  47. 0 /* chipselect */
  48. );
  49. if (0 > (ctx->fd = open(dev_name, O_RDWR))) {
  50. applog(LOG_ERR, "KnC transport: Can not open SPI device %s: %m",
  51. dev_name);
  52. goto l_free_exit_error;
  53. }
  54. /*
  55. * spi mode
  56. */
  57. if (0 > ioctl(ctx->fd, SPI_IOC_WR_MODE, &ctx->mode))
  58. goto l_ioctl_error;
  59. if (0 > ioctl(ctx->fd, SPI_IOC_RD_MODE, &ctx->mode))
  60. goto l_ioctl_error;
  61. /*
  62. * bits per word
  63. */
  64. if (0 > ioctl(ctx->fd, SPI_IOC_WR_BITS_PER_WORD, &ctx->bits))
  65. goto l_ioctl_error;
  66. if (0 > ioctl(ctx->fd, SPI_IOC_RD_BITS_PER_WORD, &ctx->bits))
  67. goto l_ioctl_error;
  68. /*
  69. * max speed hz
  70. */
  71. if (0 > ioctl(ctx->fd, SPI_IOC_WR_MAX_SPEED_HZ, &ctx->speed))
  72. goto l_ioctl_error;
  73. if (0 > ioctl(ctx->fd, SPI_IOC_RD_MAX_SPEED_HZ, &ctx->speed))
  74. goto l_ioctl_error;
  75. applog(LOG_INFO, "KnC transport: SPI device %s uses mode %hhu, bits %hhu, speed %u",
  76. dev_name, ctx->mode, ctx->bits, ctx->speed);
  77. return ctx;
  78. l_ioctl_error:
  79. applog(LOG_ERR, "KnC transport: ioctl error on SPI device %s: %m", dev_name);
  80. close(ctx->fd);
  81. l_free_exit_error:
  82. free(ctx);
  83. l_exit_error:
  84. return NULL;
  85. }
  86. void knc_trnsp_free(void *opaque_ctx)
  87. {
  88. struct spidev_context *ctx = opaque_ctx;
  89. if (NULL == ctx)
  90. return;
  91. close(ctx->fd);
  92. free(ctx);
  93. }
  94. int knc_trnsp_transfer(void *opaque_ctx, uint8_t *txbuf, uint8_t *rxbuf, int len)
  95. {
  96. struct spidev_context *ctx = opaque_ctx;
  97. struct spi_ioc_transfer xfr;
  98. int ret;
  99. memset(rxbuf, 0xff, len);
  100. ret = len;
  101. xfr.tx_buf = (unsigned long)txbuf;
  102. xfr.rx_buf = (unsigned long)rxbuf;
  103. xfr.len = len;
  104. xfr.speed_hz = ctx->speed;
  105. xfr.delay_usecs = ctx->delay;
  106. xfr.bits_per_word = ctx->bits;
  107. xfr.cs_change = 0;
  108. xfr.pad = 0;
  109. applog(LOG_DEBUG, "KnC spi:");
  110. hexdump(txbuf, len);
  111. if (1 > (ret = ioctl(ctx->fd, SPI_IOC_MESSAGE(1), &xfr)))
  112. applog(LOG_ERR, "KnC spi xfer: ioctl error on SPI device: %m");
  113. hexdump(rxbuf, len);
  114. return ret;
  115. }
  116. bool knc_trnsp_asic_detect(void *opaque_ctx, int chip_id)
  117. {
  118. return true;
  119. }
  120. void knc_trnsp_periodic_check(void *opaque_ctx)
  121. {
  122. return;
  123. }