Project

General

Profile

Download (6.99 KB) Statistics
| Branch: | Tag: | Revision:
1 dd77bb2e Harald Welte
2 d5c4d1ed Harald Welte
/* (C) 2011-2012 by Harald Welte <laforge@gnumonks.org>
3
 *
4
 * All Rights Reserved
5
 *
6
 * This program is free software; you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation; either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
 */
19
20 5fb405d4 Harald Welte
#include <stdint.h>
21 2a2c03a7 Harald Welte
#include <stdlib.h>
22
#include <errno.h>
23 5fb405d4 Harald Welte
24 dd77bb2e Harald Welte
#include <pio/pio.h>
25 5fb405d4 Harald Welte
#include <spi/spi.h>
26 dd77bb2e Harald Welte
27 2a2c03a7 Harald Welte
#include <common.h>
28
#include <reg_field.h>
29
#include <osdr_fpga.h>
30
31 5fb405d4 Harald Welte
#define BOARD_OSDR_SPI			AT91C_BASE_SPI0
32
#define BOARD_OSDR_FPGA_SPI_NPCS	0
33
34
#define OSDR_FPGA_SPCK_MAX	1000000
35
36
#define OSDR_FPGA_NPCSCONFIG(masterClock) \
37
		(AT91C_SPI_NCPHA | AT91C_SPI_BITS_8 \
38
		 | SPI_SCBR(OSDR_FPGA_SPCK_MAX, masterClock) \
39
		 | SPI_DLYBS(50, masterClock) \
40
		 | SPI_DLYBCT(0, masterClock))
41
42 07cc0443 Harald Welte
static const Pin fon_pin = PIN_FON;
43
static AT91S_SPI *spi = BOARD_OSDR_SPI;
44
45
static void write_byte(uint8_t byte)
46
{
47
	while ((spi->SPI_SR & AT91C_SPI_TDRE) == 0) {
48
		//printf("W SR=0x%08x  ", spi->SPI_SR);
49
		if (spi->SPI_SR & AT91C_SPI_RDRF)
50
			SPI_Read(BOARD_OSDR_SPI);
51
	}
52
	spi->SPI_TDR = byte | SPI_PCS(0);
53
}
54
55
56 5fb405d4 Harald Welte
uint32_t osdr_fpga_reg_read(uint8_t reg)
57
{
58
	uint32_t val;
59
60 07cc0443 Harald Welte
	/* make sure that previous transfers have terminated */
61
	while ((spi->SPI_SR & AT91C_SPI_TXEMPTY) == 0);
62
63
	write_byte(0x80 | (reg & 0x7f));
64
	/* dummy read for command byte transfer */
65 5fb405d4 Harald Welte
	SPI_Read(BOARD_OSDR_SPI);
66
67 07cc0443 Harald Welte
	write_byte(0);
68 5fb405d4 Harald Welte
	val = SPI_Read(BOARD_OSDR_SPI) << 24;
69
70 07cc0443 Harald Welte
	write_byte(0);
71 5fb405d4 Harald Welte
	val |= SPI_Read(BOARD_OSDR_SPI) << 16;
72
73 07cc0443 Harald Welte
	write_byte(0);
74 5fb405d4 Harald Welte
	val |= SPI_Read(BOARD_OSDR_SPI) << 8;
75
76 07cc0443 Harald Welte
	write_byte(0);
77 5fb405d4 Harald Welte
	val |= SPI_Read(BOARD_OSDR_SPI);
78
79
	return val;
80
}
81
82
void osdr_fpga_reg_write(uint8_t reg, uint32_t val)
83
{
84 07cc0443 Harald Welte
	/* make sure that previous transfers have terminated */
85
	while ((spi->SPI_SR & AT91C_SPI_TXEMPTY) == 0);
86 5fb405d4 Harald Welte
87 07cc0443 Harald Welte
	write_byte(reg & 0x7f);
88
	write_byte((val >> 24) & 0xff);
89
	write_byte((val >> 16) & 0xff);
90
	write_byte((val >> 8) & 0xff);
91
	write_byte((val >> 0) & 0xff);
92 5fb405d4 Harald Welte
93 07cc0443 Harald Welte
	/* wait until transfer has finished */
94 5fb405d4 Harald Welte
	while (!SPI_IsFinished(BOARD_OSDR_SPI));
95
96 07cc0443 Harald Welte
	/* make sure to flush any received characters */
97
	while (spi->SPI_SR & AT91C_SPI_RDRF)
98
		SPI_Read(BOARD_OSDR_SPI);
99 5fb405d4 Harald Welte
}
100 2a2c03a7 Harald Welte
101
void osdr_fpga_power(int on)
102
{
103
	if (on)
104
		PIO_Set(&fon_pin);
105
	else
106
		PIO_Clear(&fon_pin);
107
}
108
109 399d4147 Christian Daniel
void osdr_fpga_set_decimation(uint8_t val)
110
{
111
	osdr_fpga_reg_write(OSDR_FPGA_REG_DECIMATION, val);
112
}
113
114
void osdr_fpga_set_iq_swap(uint8_t val)
115
{
116
	osdr_fpga_reg_write(OSDR_FPGA_REG_IQ_SWAP, (val & 1) ^ 1);
117
}
118
119
void osdr_fpga_set_iq_gain(uint16_t igain, uint16_t qgain)
120
{
121
	osdr_fpga_reg_write(OSDR_FPGA_REG_IQ_GAIN, ((uint32_t)igain) | (((uint32_t)qgain) << 16));
122
}
123
124
void osdr_fpga_set_iq_ofs(int16_t iofs, int16_t qofs)
125
{
126
	osdr_fpga_reg_write(OSDR_FPGA_REG_IQ_OFS, (((uint32_t)iofs) & 0xffff) | ((((uint32_t)qofs) << 16) & 0xffff0000));
127
}
128
129 2a2c03a7 Harald Welte
130
/***********************************************************************
131
 * command integration
132
 ***********************************************************************/
133
134
static int cmd_fpga_dump(struct cmd_state *cs, enum cmd_op op,
135
			 const char *cmd, int argc, char **argv)
136
{
137
138
	uart_cmd_out(cs, "FPGA ID REG: 0x%08x\n\r", osdr_fpga_reg_read(OSDR_FPGA_REG_ID));
139
	uart_cmd_out(cs, "FPGA ADC: 0x%08x\n\r", osdr_fpga_reg_read(OSDR_FPGA_REG_ADC_VAL));
140
	uart_cmd_out(cs, "FPGA PWM1: 0x%08x\n\r", osdr_fpga_reg_read(OSDR_FPGA_REG_PWM1));
141
	uart_cmd_out(cs, "FPGA ADC TIMING: 0x%08x\n\r", osdr_fpga_reg_read(OSDR_FPGA_REG_ADC_TIMING));
142
143
	return 0;
144
}
145
146
static int cmd_fpga_clkdiv(struct cmd_state *cs, enum cmd_op op,
147
			   const char *cmd, int argc, char **argv)
148
{
149
	uint32_t tmp;
150
151
	if (argc < 1)
152
		return -EINVAL;
153
154
	tmp = osdr_fpga_reg_read(OSDR_FPGA_REG_ADC_TIMING);
155
	osdr_fpga_reg_write(OSDR_FPGA_REG_ADC_TIMING,
156
			    (tmp & 0xFFFF0000) | atoi(argv[0]));
157
158
	return 0;
159
}
160
161
enum fpga_field {
162
	PWM1_DIV, PWM1_DUTY,
163
	PWM2_DIV, PWM2_DUTY,
164
	ADC_CLKDIV, ADC_DUTY,
165
};
166
167
const struct reg_field fpga_fields[] = {
168
	[PWM1_DIV] = { OSDR_FPGA_REG_PWM1, 0, 16 },
169
	[PWM1_DUTY] = { OSDR_FPGA_REG_PWM1, 16, 16 },
170
	[PWM2_DIV] = { OSDR_FPGA_REG_PWM2, 0, 16 },
171
	[PWM2_DUTY] = { OSDR_FPGA_REG_PWM2, 16, 16 },
172
	[ADC_CLKDIV] = { OSDR_FPGA_REG_ADC_TIMING, 0, 8 },
173
	[ADC_DUTY] = { OSDR_FPGA_REG_ADC_TIMING, 8, 8},
174
};
175
176
const char *field_names[] = {
177
	[PWM1_DIV] = 	"fpga.pwm1_div",
178
	[PWM1_DUTY] =	"fpga.pwm1_duty",
179
      	[PWM2_DIV] =	"fpga.pwm2_div",
180
	[PWM2_DUTY] =	"fpga.pwm2_duty",
181
	[ADC_CLKDIV] =	"fpga.adc_clkdiv",
182
	[ADC_DUTY] =	"fpga.adc_acqlen",
183
};
184
185
static int fpga_f_write(void *data, uint32_t reg, uint32_t val)
186
{
187
	osdr_fpga_reg_write(reg, val);
188
	return 0;
189
}
190
191
static uint32_t fpga_f_read(void *data, uint32_t reg)
192
{
193
	return osdr_fpga_reg_read(reg);
194
}
195
196
static const struct reg_field_ops fpga_fops = {
197
	.fields		= fpga_fields,
198
	.field_names	= field_names,
199
	.num_fields	= ARRAY_SIZE(fpga_fields),
200
	.data		= NULL,
201
	.write_cb	= fpga_f_write,
202
	.read_cb	= fpga_f_read,
203
};
204
205
static int cmd_fpga_field(struct cmd_state *cs, enum cmd_op op,
206
			  const char *cmd, int argc, char **argv)
207
{
208
	return reg_field_cmd(cs, op, cmd, argc, argv, &fpga_fops);
209
}
210
211 ef60309e Harald Welte
static int cmd_fpga_test(struct cmd_state *cs, enum cmd_op op,
212
			 const char *cmd, int argc, char **argv)
213
{
214
	uint32_t on;
215
216
	/* in the test mode, the FPGA will not send samples but an incrementing
217
	 * and decrementing counter to detect lost samples. */
218
	switch (op) {
219
	case CMD_OP_SET:
220
		if (atoi(argv[0]) == 0)
221
			on = 0;
222
		else
223
			on = 1;
224
		osdr_fpga_reg_write(4, on);
225
		break;
226
	case CMD_OP_GET:
227
		printf("FPGA Test mode is %u\n\r", osdr_fpga_reg_read(4));
228
		break;
229
	}
230
	return 0;
231
}
232
233 2a2c03a7 Harald Welte
static struct cmd cmds[] = {
234
	{ "fpga.dump", CMD_OP_EXEC, cmd_fpga_dump,
235
	  "Dump FPGA registers" },
236
	{ "fpga.pwm1_div", CMD_OP_SET|CMD_OP_GET, cmd_fpga_field,
237
	  "PWM divider, Freq = 80MHz/(div+1)" },
238
	{ "fpga.pwm1_duty", CMD_OP_SET|CMD_OP_GET, cmd_fpga_field,
239
	  "PWM duty cycle" },
240
	{ "fpga.pwm2_div", CMD_OP_SET|CMD_OP_GET, cmd_fpga_field,
241
	  "PWM divider, Freq = 80MHz/(div+1)" },
242
	{ "fpga.pwm2_duty", CMD_OP_SET|CMD_OP_GET, cmd_fpga_field,
243
	  "PWM duty cycle" },
244
	{ "fpga.adc_clkdiv", CMD_OP_SET|CMD_OP_GET, cmd_fpga_field,
245
	  "FPGA Clock Divider for ADC (80 MHz/CLKDIV)" },
246
	{ "fpga.adc_acqlen", CMD_OP_SET|CMD_OP_GET, cmd_fpga_field,
247
	  "Num of SCK cycles nCS to AD7357 is held high betewen conversions" },
248 ef60309e Harald Welte
	{ "fpga.test_mode", CMD_OP_SET|CMD_OP_GET, cmd_fpga_test,
249
	  "Enable/disable test mode" },
250 2a2c03a7 Harald Welte
};
251
252
253
/***********************************************************************
254
 * global init function
255
 ***********************************************************************/
256
257
void osdr_fpga_init(uint32_t masterClock)
258
{
259
	SPI_Configure(BOARD_OSDR_SPI, AT91C_ID_SPI0,
260
			AT91C_SPI_MSTR | AT91C_SPI_PS_FIXED);
261
	SPI_ConfigureNPCS(BOARD_OSDR_SPI, 0,
262
			  OSDR_FPGA_NPCSCONFIG(masterClock));
263
	SPI_Enable(BOARD_OSDR_SPI);
264
265
	uart_cmds_register(cmds, ARRAY_SIZE(cmds));
266
}
Add picture from clipboard (Maximum size: 48.8 MB)