1 /* 2 * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, this 9 * list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * 3. Neither the name of the copyright holder nor the names of its 16 * contributors may be used to endorse or promote products derived from this 17 * software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <nrfx.h> 33 34 #if NRFX_CHECK(NRFX_QSPI_ENABLED) 35 36 #include <nrfx_qspi.h> 37 38 39 /** 40 * @brief Command byte used to read status register. 41 * 42 */ 43 #define QSPI_STD_CMD_RDSR 0x05 44 45 /** 46 * @brief Byte used to mask status register and retrieve the write-in-progess bit. 47 * 48 */ 49 #define QSPI_MEM_STATUSREG_WIP_Pos 0x01 50 51 /** 52 * @brief Default time used in timeout function. 53 */ 54 #define QSPI_DEF_WAIT_TIME_US 10 55 56 /** 57 * @brief Default number of tries in timeout function. 58 */ 59 #define QSPI_DEF_WAIT_ATTEMPTS 100 60 61 /** 62 * @brief Control block - driver instance local data. 63 */ 64 typedef struct 65 { 66 nrfx_qspi_handler_t handler; /**< Handler. */ 67 nrfx_drv_state_t state; /**< Driver state. */ 68 volatile bool interrupt_driven; /**< Information if the current operation is performed and is interrupt-driven. */ 69 void * p_context; /**< Driver context used in interrupt. */ 70 } qspi_control_block_t; 71 72 static qspi_control_block_t m_cb; 73 74 static nrfx_err_t qspi_task_perform(nrf_qspi_task_t task) 75 { 76 // Wait for peripheral 77 if (m_cb.interrupt_driven) 78 { 79 return NRFX_ERROR_BUSY; 80 } 81 82 nrf_qspi_event_clear(NRF_QSPI, NRF_QSPI_EVENT_READY); 83 84 if (m_cb.handler) 85 { 86 m_cb.interrupt_driven = true; 87 nrf_qspi_int_enable(NRF_QSPI, NRF_QSPI_INT_READY_MASK); 88 } 89 90 nrf_qspi_task_trigger(NRF_QSPI, task); 91 92 if (m_cb.handler == NULL) 93 { 94 while (!nrf_qspi_event_check(NRF_QSPI, NRF_QSPI_EVENT_READY)) 95 {}; 96 } 97 return NRFX_SUCCESS; 98 } 99 100 static bool qspi_pins_configure(nrf_qspi_pins_t const * p_config) 101 { 102 // Check if the user set meaningful values to struct fields. If not, return false. 103 if ((p_config->sck_pin == NRF_QSPI_PIN_NOT_CONNECTED) || 104 (p_config->csn_pin == NRF_QSPI_PIN_NOT_CONNECTED) || 105 (p_config->io0_pin == NRF_QSPI_PIN_NOT_CONNECTED) || 106 (p_config->io1_pin == NRF_QSPI_PIN_NOT_CONNECTED)) 107 { 108 return false; 109 } 110 111 nrf_qspi_pins_set(NRF_QSPI, p_config); 112 113 return true; 114 } 115 116 nrfx_err_t nrfx_qspi_init(nrfx_qspi_config_t const * p_config, 117 nrfx_qspi_handler_t handler, 118 void * p_context) 119 { 120 NRFX_ASSERT(p_config); 121 if (m_cb.state != NRFX_DRV_STATE_UNINITIALIZED) 122 { 123 return NRFX_ERROR_INVALID_STATE; 124 } 125 126 if (!qspi_pins_configure(&p_config->pins)) 127 { 128 return NRFX_ERROR_INVALID_PARAM; 129 } 130 131 nrf_qspi_xip_offset_set(NRF_QSPI, p_config->xip_offset); 132 nrf_qspi_ifconfig0_set(NRF_QSPI, &p_config->prot_if); 133 nrf_qspi_ifconfig1_set(NRF_QSPI, &p_config->phy_if); 134 135 m_cb.interrupt_driven = false; 136 m_cb.handler = handler; 137 m_cb.p_context = p_context; 138 139 /* QSPI interrupt is disabled because the device should be enabled in polling mode (wait for activate 140 task event ready)*/ 141 nrf_qspi_int_disable(NRF_QSPI, NRF_QSPI_INT_READY_MASK); 142 143 if (handler) 144 { 145 NRFX_IRQ_PRIORITY_SET(QSPI_IRQn, p_config->irq_priority); 146 NRFX_IRQ_ENABLE(QSPI_IRQn); 147 } 148 149 m_cb.state = NRFX_DRV_STATE_INITIALIZED; 150 151 nrf_qspi_enable(NRF_QSPI); 152 153 nrf_qspi_event_clear(NRF_QSPI, NRF_QSPI_EVENT_READY); 154 nrf_qspi_task_trigger(NRF_QSPI, NRF_QSPI_TASK_ACTIVATE); 155 156 // Waiting for the peripheral to activate 157 bool result; 158 NRFX_WAIT_FOR(nrf_qspi_event_check(NRF_QSPI, NRF_QSPI_EVENT_READY), 159 QSPI_DEF_WAIT_ATTEMPTS, 160 QSPI_DEF_WAIT_TIME_US, 161 result); 162 163 if (!result) 164 { 165 return NRFX_ERROR_TIMEOUT; 166 } 167 168 return NRFX_SUCCESS; 169 } 170 171 nrfx_err_t nrfx_qspi_cinstr_xfer(nrf_qspi_cinstr_conf_t const * p_config, 172 void const * p_tx_buffer, 173 void * p_rx_buffer) 174 { 175 NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED); 176 177 if (m_cb.interrupt_driven) 178 { 179 return NRFX_ERROR_BUSY; 180 } 181 182 nrf_qspi_event_clear(NRF_QSPI, NRF_QSPI_EVENT_READY); 183 /* In some cases, only opcode should be sent. To prevent execution, set function code is 184 * surrounded by an if. 185 */ 186 if (p_tx_buffer) 187 { 188 nrf_qspi_cinstrdata_set(NRF_QSPI, p_config->length, p_tx_buffer); 189 } 190 nrf_qspi_int_disable(NRF_QSPI, NRF_QSPI_INT_READY_MASK); 191 192 nrf_qspi_cinstr_transfer_start(NRF_QSPI, p_config); 193 194 bool result; 195 NRFX_WAIT_FOR(nrf_qspi_event_check(NRF_QSPI, NRF_QSPI_EVENT_READY), 196 QSPI_DEF_WAIT_ATTEMPTS, 197 QSPI_DEF_WAIT_TIME_US, 198 result); 199 200 if (!result) 201 { 202 // This timeout should never occur when WIPWAIT is not active, since in this 203 // case the QSPI peripheral should send the command immediately, without any 204 // waiting for previous write to complete. 205 NRFX_ASSERT(p_config->wipwait); 206 207 return NRFX_ERROR_TIMEOUT; 208 } 209 nrf_qspi_event_clear(NRF_QSPI, NRF_QSPI_EVENT_READY); 210 nrf_qspi_int_enable(NRF_QSPI, NRF_QSPI_INT_READY_MASK); 211 212 if (p_rx_buffer) 213 { 214 nrf_qspi_cinstrdata_get(NRF_QSPI, p_config->length, p_rx_buffer); 215 } 216 217 return NRFX_SUCCESS; 218 } 219 220 nrfx_err_t nrfx_qspi_cinstr_quick_send(uint8_t opcode, 221 nrf_qspi_cinstr_len_t length, 222 void const * p_tx_buffer) 223 { 224 nrf_qspi_cinstr_conf_t config = NRFX_QSPI_DEFAULT_CINSTR(opcode, length); 225 return nrfx_qspi_cinstr_xfer(&config, p_tx_buffer, NULL); 226 } 227 228 nrfx_err_t nrfx_qspi_mem_busy_check(void) 229 { 230 nrfx_err_t ret_code; 231 uint8_t status_value = 0; 232 233 nrf_qspi_cinstr_conf_t const config = 234 NRFX_QSPI_DEFAULT_CINSTR(QSPI_STD_CMD_RDSR, 235 NRF_QSPI_CINSTR_LEN_2B); 236 ret_code = nrfx_qspi_cinstr_xfer(&config, &status_value, &status_value); 237 238 if (ret_code != NRFX_SUCCESS) 239 { 240 return ret_code; 241 } 242 243 if ((status_value & QSPI_MEM_STATUSREG_WIP_Pos) != 0x00) 244 { 245 return NRFX_ERROR_BUSY; 246 } 247 248 return NRFX_SUCCESS; 249 } 250 251 void nrfx_qspi_uninit(void) 252 { 253 NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED); 254 255 nrf_qspi_int_disable(NRF_QSPI, NRF_QSPI_INT_READY_MASK); 256 257 nrf_qspi_task_trigger(NRF_QSPI, NRF_QSPI_TASK_DEACTIVATE); 258 259 nrf_qspi_disable(NRF_QSPI); 260 261 NRFX_IRQ_DISABLE(QSPI_IRQn); 262 263 nrf_qspi_event_clear(NRF_QSPI, NRF_QSPI_EVENT_READY); 264 265 m_cb.state = NRFX_DRV_STATE_UNINITIALIZED; 266 } 267 268 nrfx_err_t nrfx_qspi_write(void const * p_tx_buffer, 269 size_t tx_buffer_length, 270 uint32_t dst_address) 271 { 272 NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED); 273 NRFX_ASSERT(p_tx_buffer != NULL); 274 NRFX_ASSERT(nrfx_is_in_ram(p_tx_buffer)); 275 NRFX_ASSERT(nrfx_is_word_aligned(p_tx_buffer)); 276 277 if (!nrfx_is_in_ram(p_tx_buffer)) 278 { 279 return NRFX_ERROR_INVALID_ADDR; 280 } 281 282 nrf_qspi_write_buffer_set(NRF_QSPI, p_tx_buffer, tx_buffer_length, dst_address); 283 return qspi_task_perform(NRF_QSPI_TASK_WRITESTART); 284 285 } 286 287 nrfx_err_t nrfx_qspi_read(void * p_rx_buffer, 288 size_t rx_buffer_length, 289 uint32_t src_address) 290 { 291 NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED); 292 NRFX_ASSERT(p_rx_buffer != NULL); 293 NRFX_ASSERT(nrfx_is_in_ram(p_rx_buffer)); 294 NRFX_ASSERT(nrfx_is_word_aligned(p_rx_buffer)); 295 296 if (!nrfx_is_in_ram(p_rx_buffer)) 297 { 298 return NRFX_ERROR_INVALID_ADDR; 299 } 300 301 nrf_qspi_read_buffer_set(NRF_QSPI, p_rx_buffer, rx_buffer_length, src_address); 302 return qspi_task_perform(NRF_QSPI_TASK_READSTART); 303 } 304 305 nrfx_err_t nrfx_qspi_erase(nrf_qspi_erase_len_t length, 306 uint32_t start_address) 307 { 308 NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED); 309 nrf_qspi_erase_ptr_set(NRF_QSPI, start_address, length); 310 return qspi_task_perform(NRF_QSPI_TASK_ERASESTART); 311 } 312 313 nrfx_err_t nrfx_qspi_chip_erase(void) 314 { 315 return nrfx_qspi_erase(NRF_QSPI_ERASE_LEN_ALL, 0); 316 } 317 318 void nrfx_qspi_irq_handler(void) 319 { 320 // Catch Event ready interrupts 321 if (nrf_qspi_event_check(NRF_QSPI, NRF_QSPI_EVENT_READY)) 322 { 323 m_cb.interrupt_driven = false; 324 nrf_qspi_event_clear(NRF_QSPI, NRF_QSPI_EVENT_READY); 325 m_cb.handler(NRFX_QSPI_EVENT_DONE, m_cb.p_context); 326 } 327 } 328 329 #endif // NRFX_CHECK(NRFX_QSPI_ENABLED) 330