forked from ubiGG/bmminer
-
Notifications
You must be signed in to change notification settings - Fork 0
/
knc-transport-spi.c
148 lines (123 loc) · 3.26 KB
/
knc-transport-spi.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/*
* Direct SPI transport layer for KnCminer Jupiters
*
* Copyright 2014 KnCminer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 3 of the License, or (at your option)
* any later version. See COPYING for more details.
*/
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/spi/spidev.h>
#include "logging.h"
#include "miner.h"
#include "hexdump.c"
#include "knc-transport.h"
#define SPI_DEVICE_TEMPLATE "/dev/spidev%d.%d"
#define SPI_MODE (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH)
#define SPI_BITS_PER_WORD 8
#define SPI_MAX_SPEED 3000000
#define SPI_DELAY_USECS 0
struct spidev_context {
int fd;
uint32_t speed;
uint16_t delay;
uint8_t mode;
uint8_t bits;
};
/* Init SPI transport */
void *knc_trnsp_new(int dev_idx)
{
struct spidev_context *ctx;
char dev_name[PATH_MAX];
if (NULL == (ctx = malloc(sizeof(struct spidev_context)))) {
applog(LOG_ERR, "KnC transport: Out of memory");
goto l_exit_error;
}
ctx->mode = SPI_MODE;
ctx->bits = SPI_BITS_PER_WORD;
ctx->speed = SPI_MAX_SPEED;
ctx->delay = SPI_DELAY_USECS;
ctx->fd = -1;
sprintf(dev_name, SPI_DEVICE_TEMPLATE,
dev_idx + 1, /* bus */
0 /* chipselect */
);
if (0 > (ctx->fd = open(dev_name, O_RDWR))) {
applog(LOG_ERR, "KnC transport: Can not open SPI device %s: %m",
dev_name);
goto l_free_exit_error;
}
/*
* spi mode
*/
if (0 > ioctl(ctx->fd, SPI_IOC_WR_MODE, &ctx->mode))
goto l_ioctl_error;
if (0 > ioctl(ctx->fd, SPI_IOC_RD_MODE, &ctx->mode))
goto l_ioctl_error;
/*
* bits per word
*/
if (0 > ioctl(ctx->fd, SPI_IOC_WR_BITS_PER_WORD, &ctx->bits))
goto l_ioctl_error;
if (0 > ioctl(ctx->fd, SPI_IOC_RD_BITS_PER_WORD, &ctx->bits))
goto l_ioctl_error;
/*
* max speed hz
*/
if (0 > ioctl(ctx->fd, SPI_IOC_WR_MAX_SPEED_HZ, &ctx->speed))
goto l_ioctl_error;
if (0 > ioctl(ctx->fd, SPI_IOC_RD_MAX_SPEED_HZ, &ctx->speed))
goto l_ioctl_error;
applog(LOG_INFO, "KnC transport: SPI device %s uses mode %hhu, bits %hhu, speed %u",
dev_name, ctx->mode, ctx->bits, ctx->speed);
return ctx;
l_ioctl_error:
applog(LOG_ERR, "KnC transport: ioctl error on SPI device %s: %m", dev_name);
close(ctx->fd);
l_free_exit_error:
free(ctx);
l_exit_error:
return NULL;
}
void knc_trnsp_free(void *opaque_ctx)
{
struct spidev_context *ctx = opaque_ctx;
if (NULL == ctx)
return;
close(ctx->fd);
free(ctx);
}
int knc_trnsp_transfer(void *opaque_ctx, uint8_t *txbuf, uint8_t *rxbuf, int len)
{
struct spidev_context *ctx = opaque_ctx;
struct spi_ioc_transfer xfr;
int ret;
memset(rxbuf, 0xff, len);
ret = len;
xfr.tx_buf = (unsigned long)txbuf;
xfr.rx_buf = (unsigned long)rxbuf;
xfr.len = len;
xfr.speed_hz = ctx->speed;
xfr.delay_usecs = ctx->delay;
xfr.bits_per_word = ctx->bits;
xfr.cs_change = 0;
xfr.pad = 0;
applog(LOG_DEBUG, "KnC spi:");
hexdump(txbuf, len);
if (1 > (ret = ioctl(ctx->fd, SPI_IOC_MESSAGE(1), &xfr)))
applog(LOG_ERR, "KnC spi xfer: ioctl error on SPI device: %m");
hexdump(rxbuf, len);
return ret;
}
bool knc_trnsp_asic_detect(void *opaque_ctx, int chip_id)
{
return true;
}
void knc_trnsp_periodic_check(void *opaque_ctx)
{
return;
}