Skip to content

Commit 219d0c6

Browse files
SenRamakrimaciejbocianski
authored andcommitted
QSPI driver implementation
1 parent 009cc8b commit 219d0c6

File tree

2 files changed

+529
-0
lines changed

2 files changed

+529
-0
lines changed

drivers/QSPI.cpp

Lines changed: 297 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,297 @@
1+
/* mbed Microcontroller Library
2+
* Copyright (c) 2006-2013 ARM Limited
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
#include "drivers/QSPI.h"
17+
#include "platform/mbed_critical.h"
18+
19+
#if DEVICE_QSPI
20+
#define IS_BUS_WIDTH_VALID(width) ((width == 1) || (width == 2) || (width == 4))
21+
#define IS_SIZE_VALID(size) ((size == 8) || (size == 16) || (size == 24) || (size == 32))
22+
#define IS_ALT_SIZE_VALID(alt_size) ((alt_size == 0) || (alt_size == 8) || (alt_size == 16) || (alt_size == 24) || (alt_size == 32))
23+
24+
namespace mbed {
25+
26+
QSPI* QSPI::_owner = NULL;
27+
SingletonPtr<PlatformMutex> QSPI::_mutex;
28+
29+
QSPI::QSPI(PinName io0, PinName io1, PinName io2, PinName io3, PinName sclk, PinName ssel) :
30+
_qspi(),
31+
_inst_width(QSPI_DEFAULT_INST_WIDTH),
32+
_address_width(QSPI_DEFAULT_ADDRESS_WIDTH),
33+
_address_size(QSPI_DEFAULT_ADDRESS_SIZE),
34+
_alt_width(QSPI_DEFAULT_ALT_WIDTH),
35+
_alt_size(QSPI_DEFAULT_ALT_SIZE),
36+
_data_width(QSPI_DEFAULT_DATA_WIDTH),
37+
_num_dummy_cycles(QSPI_DEFAULT_DUMMY_CYCLES),
38+
_hz(QSPI_DEFAULT_HZ) {
39+
// No lock needed in the constructor
40+
_qspi_io0 = io0;
41+
_qspi_io1 = io1;
42+
_qspi_io2 = io2;
43+
_qspi_io3 = io3;
44+
_qspi_clk = sclk;
45+
_qspi_cs = ssel;
46+
}
47+
48+
bool QSPI::configure_format(int inst_width,
49+
int address_width, int address_size,
50+
int alt_width, int alt_size,
51+
int data_width,
52+
int dummy_cycles,
53+
int mode ) {
54+
if(!IS_BUS_WIDTH_VALID(inst_width)) return false;
55+
if(!IS_BUS_WIDTH_VALID(address_width)) return false;
56+
if(!IS_SIZE_VALID(address_size)) return false;
57+
if(!IS_BUS_WIDTH_VALID(alt_width)) return false;
58+
if(!IS_ALT_SIZE_VALID(alt_size)) return false;
59+
if(!IS_BUS_WIDTH_VALID(data_width)) return false;
60+
if(dummy_cycles < 0) return false;
61+
if(mode != 0 && mode != 1) return false;
62+
63+
lock();
64+
switch(inst_width) {
65+
case 1:_inst_width = QSPI_CFG_BUS_SINGLE; break;
66+
case 2:_inst_width = QSPI_CFG_BUS_DUAL; break;
67+
case 4:_inst_width = QSPI_CFG_BUS_QUAD; break;
68+
default:_inst_width = QSPI_CFG_BUS_SINGLE;
69+
}
70+
71+
switch(address_width) {
72+
case 1:_address_width = QSPI_CFG_BUS_SINGLE; break;
73+
case 2:_address_width = QSPI_CFG_BUS_DUAL; break;
74+
case 4:_address_width = QSPI_CFG_BUS_QUAD; break;
75+
default:_address_width = QSPI_CFG_BUS_SINGLE;
76+
}
77+
78+
switch(address_size) {
79+
case 8:_address_size = QSPI_CFG_ADDR_SIZE_8; break;
80+
case 16:_address_size = QSPI_CFG_ADDR_SIZE_16; break;
81+
case 24:_address_size = QSPI_CFG_ADDR_SIZE_24; break;
82+
case 32:_address_size = QSPI_CFG_ADDR_SIZE_32; break;
83+
default:_address_size = QSPI_CFG_ADDR_SIZE_8;
84+
}
85+
86+
switch(alt_width) {
87+
case 1:_alt_width = QSPI_CFG_BUS_SINGLE; break;
88+
case 2:_alt_width = QSPI_CFG_BUS_DUAL; break;
89+
case 4:_alt_width = QSPI_CFG_BUS_QUAD; break;
90+
default:_alt_width = QSPI_CFG_BUS_SINGLE;
91+
}
92+
93+
switch(alt_size) {
94+
case 0:_alt_size = QSPI_CFG_ALT_SIZE_NONE; break;
95+
case 8:_alt_size = QSPI_CFG_ALT_SIZE_8; break;
96+
case 16:_alt_size = QSPI_CFG_ALT_SIZE_16; break;
97+
case 24:_alt_size = QSPI_CFG_ALT_SIZE_24; break;
98+
case 32:_alt_size = QSPI_CFG_ALT_SIZE_32; break;
99+
default:_alt_size = QSPI_CFG_ALT_SIZE_NONE;
100+
}
101+
102+
switch(data_width) {
103+
case 1:_data_width = QSPI_CFG_BUS_SINGLE; break;
104+
case 2:_data_width = QSPI_CFG_BUS_DUAL; break;
105+
case 4:_data_width = QSPI_CFG_BUS_QUAD; break;
106+
default:_data_width = QSPI_CFG_BUS_SINGLE;
107+
}
108+
109+
_num_dummy_cycles = dummy_cycles;
110+
_mode = mode;
111+
unlock();
112+
113+
return true;
114+
}
115+
116+
bool QSPI::set_frequency(int hz) {
117+
118+
lock();
119+
_hz = hz;
120+
121+
//If the same owner, just change freq.
122+
//Otherwise we may have to change mode as well, so call _acquire
123+
if (_owner == this) {
124+
qspi_frequency(&_qspi, _hz);
125+
} else {
126+
_acquire();
127+
}
128+
unlock();
129+
130+
return true;
131+
}
132+
133+
bool QSPI::initialize() {
134+
lock();
135+
qspi_status_t ret = qspi_init(&_qspi, _qspi_io0, _qspi_io1, _qspi_io2, _qspi_io3, _qspi_clk, _qspi_cs, _hz, _mode );
136+
unlock();
137+
138+
return ( ret == QSPI_STATUS_OK )? true:false;
139+
}
140+
141+
int QSPI::read(unsigned int address, char *rx_buffer, size_t *rx_length) {
142+
int ret = 0;
143+
144+
if( (rx_length != NULL) && (rx_buffer != NULL) ) {
145+
if(*rx_length != 0) {
146+
lock();
147+
if( true == _acquire()) {
148+
qspi_command_t *qspi_cmd = _build_qspi_command(-1, address, -1);
149+
if(QSPI_STATUS_OK == qspi_read(&_qspi, qspi_cmd, rx_buffer, rx_length)) {
150+
ret = 1;
151+
}
152+
}
153+
unlock();
154+
}
155+
}
156+
157+
return ret;
158+
}
159+
160+
int QSPI::write(unsigned int address, const char *tx_buffer, size_t *tx_length) {
161+
int ret = 0;
162+
163+
if( (tx_length != NULL) && (tx_buffer != NULL) ) {
164+
if(*tx_length != 0) {
165+
lock();
166+
if(true == _acquire()) {
167+
qspi_command_t *qspi_cmd = _build_qspi_command(-1, address, -1);
168+
if(QSPI_STATUS_OK == qspi_write(&_qspi, qspi_cmd, tx_buffer, tx_length)) {
169+
ret = 1;
170+
}
171+
}
172+
unlock();
173+
}
174+
}
175+
176+
return ret;
177+
}
178+
179+
int QSPI::read(unsigned int instruction, unsigned int address, unsigned int alt, char *rx_buffer, size_t *rx_length) {
180+
int ret = 0;
181+
182+
if( (rx_length != NULL) && (rx_buffer != NULL) ) {
183+
if(*rx_length != 0) {
184+
lock();
185+
if( true == _acquire()) {
186+
qspi_command_t *qspi_cmd = _build_qspi_command(instruction, address, alt);
187+
if(QSPI_STATUS_OK == qspi_read(&_qspi, qspi_cmd, rx_buffer, rx_length)) {
188+
ret = 1;
189+
}
190+
}
191+
unlock();
192+
}
193+
}
194+
195+
return ret;
196+
}
197+
198+
int QSPI::write(unsigned int instruction, unsigned int address, unsigned int alt, const char *tx_buffer, size_t *tx_length) {
199+
int ret = 0;
200+
201+
if( (tx_length != NULL) && (tx_buffer != NULL) ) {
202+
if(*tx_length != 0) {
203+
lock();
204+
if(true == _acquire()) {
205+
qspi_command_t *qspi_cmd = _build_qspi_command(instruction, address, alt);
206+
if(QSPI_STATUS_OK == qspi_write(&_qspi, qspi_cmd, tx_buffer, tx_length)) {
207+
ret = 1;
208+
}
209+
}
210+
unlock();
211+
}
212+
}
213+
214+
return ret;
215+
}
216+
217+
int QSPI::command_transfer(unsigned int instruction, const char *tx_buffer, size_t tx_length, const char *rx_buffer, size_t rx_length) {
218+
int ret = 1;
219+
220+
lock();
221+
if(true == _acquire()) {
222+
qspi_command_t *qspi_cmd = _build_qspi_command(instruction, -1, -1); //We just need the command
223+
if(QSPI_STATUS_OK != qspi_command_transfer(&_qspi, qspi_cmd, (const void *)tx_buffer, tx_length, (void *)rx_buffer, rx_length)) {
224+
//We got error status, return 0
225+
ret = 0;
226+
}
227+
} else {
228+
ret = 0;
229+
}
230+
unlock();
231+
232+
return ret;
233+
}
234+
235+
void QSPI::lock() {
236+
_mutex->lock();
237+
}
238+
239+
void QSPI::unlock() {
240+
_mutex->unlock();
241+
}
242+
243+
// Note: Private function with no locking
244+
bool QSPI::_acquire() {
245+
qspi_status_t ret = QSPI_STATUS_OK;
246+
247+
if (_owner != this) {
248+
//This will set freq as well
249+
ret = qspi_init(&_qspi, _qspi_io0, _qspi_io1, _qspi_io2, _qspi_io3, _qspi_clk, _qspi_cs, _hz, _mode );
250+
_owner = this;
251+
}
252+
253+
return ( ret == QSPI_STATUS_OK )? true:false;
254+
}
255+
256+
qspi_command_t *QSPI::_build_qspi_command(int instruction, int address, int alt) {
257+
258+
memset( &_qspi_command, 0, sizeof(qspi_command_t) );
259+
//Set up instruction phase parameters
260+
_qspi_command.instruction.bus_width = _inst_width;
261+
if(instruction != -1) {
262+
_qspi_command.instruction.value = instruction;
263+
} else {
264+
_qspi_command.instruction.value = 0;
265+
}
266+
267+
//Set up address phase parameters
268+
_qspi_command.address.bus_width = _address_width;
269+
_qspi_command.address.size = _address_size;
270+
if(address != -1) {
271+
_qspi_command.address.value = address;
272+
} else {
273+
_qspi_command.address.value = 0;
274+
}
275+
276+
//Set up alt phase parameters
277+
_qspi_command.alt.bus_width = _alt_width;
278+
_qspi_command.alt.size = _alt_size;
279+
if(alt != -1) {
280+
_qspi_command.alt.value = alt;
281+
} else {
282+
//In the case alt phase is absent, set the alt size to be NONE
283+
_qspi_command.alt.value = 0;
284+
}
285+
286+
//Set up dummy cycle count
287+
_qspi_command.dummy_count = _num_dummy_cycles;
288+
289+
//Set up bus width for data phase
290+
_qspi_command.data.bus_width = _data_width;
291+
292+
return &_qspi_command;
293+
}
294+
295+
} // namespace mbed
296+
297+
#endif

0 commit comments

Comments
 (0)