/ 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