aboutsummaryrefslogtreecommitdiff
path: root/src/spi.c
blob: 8acbf19991ba5c97966a35eb2e3cc7e3934a2ddf (plain)
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
#include "spi.h"
#include "gpio.h"
#include "register.h"

#define WRITE_SPI_REG(spi, reg, value) (WRITE_REGISTER(spi_base_addresses[spi], reg, value))
#define READ_SPI_REG(spi, reg) (READ_REGISTER(spi_base_addresses[spi], reg))

enum spi_register {
	TASKS_START = 0x10,
	TASKS_STOP = 0x14,
	TASKS_SUSPEND = 0x1c,
	TASKS_RESUME = 0x20,
	EVENTS_STOPPED = 0x104,
	EVENTS_ENDRX = 0x110,
	EVENTS_END = 0x118,
	EVENTS_ENDTX = 0x120,
	EVENTS_STARTED = 0x14c,
	SHORTS = 0x200,
	INTENSET = 0x304,
	INTENCLR = 0x308,
	ENABLE = 0x500,
	PSEL_SCK = 0x508,
	PSEL_MOSI = 0x50c,
	PSEL_MISO = 0x510,
	FREQUENCY = 0x524,
	RXD_PTR = 0x534,
	RXD_MAXCNT = 0x538,
	RXD_AMOUNT = 0x53c,
	RXD_LIST = 0x540,
	TXD_PTR = 0x544,
	TXD_MAXCNT = 0x548,
	TXD_AMOUNT = 0x54c,
	TXD_LIST = 0x550,
	CONFIG = 0x544,
	ORC = 0x5c0,
};

static const hwaddr spi_base_addresses[] = {
	[SPI_0] = 0x40003000,
	[SPI_1] = 0x40004000,
	[SPI_2] = 0x40023000,
};

static const u32 frequency_register_values[] = {
	[K125] = 0x02000000,
	[K250] = 0x04000000,
	[K500] = 0x08000000,
	[M1] = 0x10000000,
	[M2] = 0x20000000,
	[M4] = 0x40000000,
	[M8] = 0x80000000,
};

void spi_master_init(enum spi_interface spi, enum gpio_pin clock, enum gpio_pin mosi, enum gpio_pin miso, enum spi_bits_order order, enum spi_clock_polarity polarity, enum spi_clock_phase phase, enum spi_frequency frequency, char overread_char) {
	/* Setup GPIO pins */
	gpio_output_pin_init(clock, S0S1);
	WRITE_SPI_REG(spi, PSEL_SCK, (0xffffffff >> 1) & (0xffffffe0 | clock));
	gpio_output_pin_init(mosi, S0S1);
	WRITE_SPI_REG(spi, PSEL_MOSI, (0xffffffff >> 1) & (0xffffffe0 | mosi));
	gpio_input_pin_init(miso, PULL_DOWN, HIGH);
	WRITE_SPI_REG(spi, PSEL_MISO, (0xffffffff >> 1) & (0xffffffe0 | miso));

	/* Configure communication behaviour */
	u32 spi_config = 0x0;
	spi_config |= order;
	spi_config |= phase << 1;
	spi_config |= polarity << 2;
	WRITE_SPI_REG(spi, CONFIG, spi_config);

	WRITE_SPI_REG(spi, RXD_MAXCNT, MAX_TRANSFER_SIZE);
	WRITE_SPI_REG(spi, TXD_MAXCNT, MAX_TRANSFER_SIZE);
	WRITE_SPI_REG(spi, FREQUENCY, frequency_register_values[frequency]);
	WRITE_SPI_REG(spi, ORC, overread_char);

	/* Enable SPI Master */
	WRITE_SPI_REG(spi, ENABLE, 0x7);
}

u8 spi_master_transfer(enum spi_interface spi, u8 tx_size, u8 tx[], u8 rx_size, u8 rx[]) {
	u32 events_started_reg = 0;
	u32 events_end_reg = 0;

	WRITE_SPI_REG(spi, RXD_MAXCNT, rx_size & 0xff);
	WRITE_SPI_REG(spi, TXD_MAXCNT, tx_size & 0xff);
	WRITE_SPI_REG(spi, RXD_PTR, (hwaddr) rx);
	WRITE_SPI_REG(spi, TXD_PTR, (hwaddr) tx);

	WRITE_SPI_REG(spi, TASKS_START, 0x1);
	do {
		events_started_reg = READ_SPI_REG(spi, EVENTS_STARTED);
	} while (events_started_reg == 0);

	do {
		events_end_reg = READ_SPI_REG(spi, EVENTS_END);
	} while (events_end_reg == 0);
	
	return 0;
}

void spi_master_stop(enum spi_interface spi, enum gpio_pin clock, enum gpio_pin mosi, enum gpio_pin miso) {
	u32 events_stopped_reg = 0;

	WRITE_SPI_REG(spi, TASKS_STOP, 0x1);
	do {
		events_stopped_reg = READ_SPI_REG(spi, EVENTS_STOPPED);
	} while (events_stopped_reg == 0);

	/* Disable SPI*/
	WRITE_SPI_REG(spi, ENABLE, 0x0);
	
	/* Set configuration registers to reset values */
	WRITE_SPI_REG(spi, CONFIG, 0x0);
	WRITE_SPI_REG(spi, RXD_MAXCNT, 0x0);
	WRITE_SPI_REG(spi, TXD_MAXCNT, 0x0);
	WRITE_SPI_REG(spi, FREQUENCY, frequency_register_values[K250]);
	WRITE_SPI_REG(spi, ORC, 0x0);

	/* Free GPIO pins */
	WRITE_SPI_REG(spi, PSEL_SCK, 0xffffffff);
	gpio_pin_disable(clock);
	WRITE_SPI_REG(spi, PSEL_MOSI, 0xffffffff);
	gpio_pin_disable(mosi);
	WRITE_SPI_REG(spi, PSEL_MISO, 0xffffffff);
	gpio_pin_disable(miso);
}