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