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 #ifndef NRFX_QSPI_H__
33 #define NRFX_QSPI_H__
34 
35 #include <nrfx.h>
36 #include <hal/nrf_qspi.h>
37 
38 #ifdef __cplusplus
39 extern "C" {
40 #endif
41 
42 /**
43  * @defgroup nrfx_qspi QSPI driver
44  * @{
45  * @ingroup nrf_qspi
46  * @brief   Quad Serial Peripheral Interface (QSPI) peripheral driver.
47  */
48 
49 /**
50  * @brief QSPI driver instance configuration structure.
51  */
52 typedef struct
53 {
54     uint32_t             xip_offset;   /**< Address offset into the external memory for Execute in Place operation. */
55     nrf_qspi_pins_t      pins;         /**< Pins configuration structure. */
56     nrf_qspi_prot_conf_t prot_if;      /**< Protocol layer interface configuration structure. */
57     nrf_qspi_phy_conf_t  phy_if;       /**< Physical layer interface configuration structure. */
58     uint8_t              irq_priority; /**< Interrupt priority. */
59 } nrfx_qspi_config_t;
60 
61 /**
62  * @brief QSPI instance default configuration.
63  */
64 #define NRFX_QSPI_DEFAULT_CONFIG                                        \
65 {                                                                       \
66     .xip_offset  = NRFX_QSPI_CONFIG_XIP_OFFSET,                         \
67     .pins = {                                                           \
68        .sck_pin     = NRFX_QSPI_PIN_SCK,                                \
69        .csn_pin     = NRFX_QSPI_PIN_CSN,                                \
70        .io0_pin     = NRFX_QSPI_PIN_IO0,                                \
71        .io1_pin     = NRFX_QSPI_PIN_IO1,                                \
72        .io2_pin     = NRFX_QSPI_PIN_IO2,                                \
73        .io3_pin     = NRFX_QSPI_PIN_IO3,                                \
74     },                                                                  \
75     .irq_priority   = (uint8_t)NRFX_QSPI_CONFIG_IRQ_PRIORITY,           \
76     .prot_if = {                                                        \
77         .readoc     = (nrf_qspi_readoc_t)NRFX_QSPI_CONFIG_READOC,       \
78         .writeoc    = (nrf_qspi_writeoc_t)NRFX_QSPI_CONFIG_WRITEOC,     \
79         .addrmode   = (nrf_qspi_addrmode_t)NRFX_QSPI_CONFIG_ADDRMODE,   \
80         .dpmconfig  = false,                                            \
81     },                                                                  \
82     .phy_if = {                                                         \
83         .sck_freq   = (nrf_qspi_frequency_t)NRFX_QSPI_CONFIG_FREQUENCY, \
84         .sck_delay  = (uint8_t)NRFX_QSPI_CONFIG_SCK_DELAY,              \
85         .spi_mode   = (nrf_qspi_spi_mode_t)NRFX_QSPI_CONFIG_MODE,       \
86         .dpmen      = false                                             \
87     },                                                                  \
88 }
89 
90 /**
91  * @brief QSPI custom instruction helper with default configuration.
92  */
93 #define NRFX_QSPI_DEFAULT_CINSTR(opc, len) \
94 {                                          \
95     .opcode    = (opc),                    \
96     .length    = (len),                    \
97     .io2_level = false,                    \
98     .io3_level = false,                    \
99     .wipwait   = false,                    \
100     .wren      = false                     \
101 }
102 
103 /**
104  * @brief QSPI master driver event types, passed to the handler routine provided
105  *        during initialization.
106  */
107 typedef enum
108 {
109     NRFX_QSPI_EVENT_DONE, /**< Transfer done. */
110 } nrfx_qspi_evt_t;
111 
112 /**
113  * @brief QSPI driver event handler type.
114  */
115 typedef void (*nrfx_qspi_handler_t)(nrfx_qspi_evt_t event, void * p_context);
116 
117 /**
118  * @brief Function for initializing the QSPI driver instance.
119  *
120  * This function configures the peripheral and its interrupts and activates it. During the
121  * activation process, the internal clocks are started and the QSPI peripheral tries to read
122  * the status byte to read the busy bit. Reading the status byte is done in a simple poll and wait
123  * mechanism.
124  * If the busy bit is 1, this indicates issues with the external memory device. As a result,
125  * @ref nrfx_qspi_init returns NRFX_ERROR_TIMEOUT.
126  *
127  * In case of issues:
128  * - Check the connection.
129  * - Make sure that the memory device does not perform other operations like erasing or writing.
130  * - Check if there is a short circuit.
131  *
132  * @param[in] p_config   Pointer to the structure with initial configuration.
133  * @param[in] handler    Event handler provided by the user. If NULL, transfers
134  *                       will be performed in blocking mode.
135  * @param[in] p_context  Pointer to context. Use in interrupt handler.
136  *
137  * @retval NRFX_SUCCESS             If initialization was successful.
138  * @retval NRFX_ERROR_TIMEOUT       If the peripheral cannot connect with external memory.
139  * @retval NRFX_ERROR_INVALID_STATE If the driver was already initialized.
140  * @retval NRFX_ERROR_INVALID_PARAM If the pin configuration was incorrect.
141  */
142 nrfx_err_t nrfx_qspi_init(nrfx_qspi_config_t const * p_config,
143                           nrfx_qspi_handler_t        handler,
144                           void *                     p_context);
145 
146 /**
147  * @brief Function for uninitializing the QSPI driver instance.
148  */
149 void nrfx_qspi_uninit(void);
150 
151 /**
152  * @brief Function for reading data from QSPI memory.
153  *
154  * Write, read, and erase operations check memory device busy state before starting the operation.
155  * If the memory is busy, the resulting action depends on the mode in which the read operation is used:
156  *  - blocking mode (without handler) - a delay occurs until the last operation still runs and
157  *    until operation data is still being read.
158  *  - interrupt mode (with handler) - event emission occurs after the last operation
159  *    and reading of data are finished.
160  *
161  * @param[out] p_rx_buffer      Pointer to the receive buffer.
162  * @param[in]  rx_buffer_length Size of the data to read.
163  * @param[in]  src_address      Address in memory to read from.
164  *
165  * @retval NRFX_SUCCESS            If the operation was successful (blocking mode) or operation
166  *                                 was commissioned (handler mode).
167  * @retval NRFX_ERROR_BUSY         If the driver currently handles another operation.
168  * @retval NRFX_ERROR_INVALID_ADDR If the provided buffer is not placed in the Data RAM region.
169  */
170 nrfx_err_t nrfx_qspi_read(void *   p_rx_buffer,
171                           size_t   rx_buffer_length,
172                           uint32_t src_address);
173 
174 /**
175  * @brief Function for writing data to QSPI memory.
176  *
177  * Write, read, and erase operations check memory device busy state before starting the operation.
178  * If the memory is busy, the resulting action depends on the mode in which the write operation is used:
179  *  - blocking mode (without handler) - a delay occurs until the last operation still runs and
180  *    until operation data is still being sent.
181  *  - interrupt mode (with handler) - event emission occurs after the last operation
182  *    and sending of operation data are finished.
183  * To manually control operation execution in the memory device, use @ref nrfx_qspi_mem_busy_check
184  * after executing the write function.
185  * Remember that an incoming event signalizes only that data was sent to the memory device and the periheral
186  * before the write operation checked if memory was busy.
187  *
188  * @param[in] p_tx_buffer      Pointer to the writing buffer.
189  * @param[in] tx_buffer_length Size of the data to write.
190  * @param[in] dst_address      Address in memory to write to.
191  *
192  * @retval NRFX_SUCCESS            If the operation was successful (blocking mode) or operation
193  *                                 was commissioned (handler mode).
194  * @retval NRFX_ERROR_BUSY         If the driver currently handles other operation.
195  * @retval NRFX_ERROR_INVALID_ADDR If the provided buffer is not placed in the Data RAM region.
196  */
197 nrfx_err_t nrfx_qspi_write(void const * p_tx_buffer,
198                            size_t       tx_buffer_length,
199                            uint32_t     dst_address);
200 
201 /**
202  * @brief Function for starting erasing of one memory block - 4KB, 64KB, or the whole chip.
203  *
204  * Write, read, and erase operations check memory device busy state before starting the operation.
205  * If the memory is busy, the resulting action depends on the mode in which the erase operation is used:
206  *  - blocking mode (without handler) - a delay occurs until the last operation still runs and
207  *    until operation data is still being sent.
208  *  - interrupt mode (with handler) - event emission occurs after the last operation
209  *    and sending of operation data are finished.
210  * To manually control operation execution in the memory device, use @ref nrfx_qspi_mem_busy_check
211  * after executing the erase function.
212  * Remember that an incoming event signalizes only that data was sent to the memory device and the periheral
213  * before the erase operation checked if memory was busy.
214  *
215  * @param[in] length        Size of data to erase. See @ref nrf_qspi_erase_len_t.
216  * @param[in] start_address Memory address to start erasing. If chip erase is performed, address
217  *                          field is ommited.
218  *
219  * @retval NRFX_SUCCESS    If the operation was successful (blocking mode) or operation
220  *                         was commissioned (handler mode).
221  * @retval NRFX_ERROR_BUSY If the driver currently handles another operation.
222  */
223 nrfx_err_t nrfx_qspi_erase(nrf_qspi_erase_len_t length,
224                            uint32_t             start_address);
225 
226 /**
227  * @brief Function for starting an erase operation of the whole chip.
228  *
229  * @retval NRFX_SUCCESS    If the operation was successful (blocking mode) or operation
230  *                         was commissioned (handler mode).
231  * @retval NRFX_ERROR_BUSY If the driver currently handles another operation.
232  */
233 nrfx_err_t nrfx_qspi_chip_erase(void);
234 
235 /**
236  * @brief Function for getting the current driver status and status byte of memory device with
237  *        testing WIP (write in progress) bit.
238  *
239  * @retval NRFX_SUCCESS    If the driver and memory are ready to handle a new operation.
240  * @retval NRFX_ERROR_BUSY If the driver or memory currently handle another operation.
241  */
242 nrfx_err_t nrfx_qspi_mem_busy_check(void);
243 
244 /**
245  * @brief Function for sending operation code, sending data, and receiving data from the memory device.
246  *
247  * Use this function to transfer configuration data to memory and to receive data from memory.
248  * Pointers can be addresses from flash memory.
249  * This function is a synchronous function and should be used only if necessary.
250  *
251  * @param[in]  p_config    Pointer to the structure with opcode and transfer configuration.
252  * @param[in]  p_tx_buffer Pointer to the array with data to send. Can be NULL if only opcode is transmitted.
253  * @param[out] p_rx_buffer Pointer to the array for data to receive. Can be NULL if there is nothing to receive.
254  *
255  * @retval NRFX_SUCCESS            If the operation was successful.
256  * @retval NRFX_ERROR_TIMEOUT      If the external memory is busy or there are connection issues.
257  * @retval NRFX_ERROR_BUSY         If the driver currently handles other operation.
258  */
259 nrfx_err_t nrfx_qspi_cinstr_xfer(nrf_qspi_cinstr_conf_t const * p_config,
260                                  void const *                   p_tx_buffer,
261                                  void *                         p_rx_buffer);
262 /**
263  * @brief Function for sending operation code and data to the memory device with simpler configuration.
264  *
265  * Use this function to transfer configuration data to memory and to receive data from memory.
266  * This function is a synchronous function and should be used only if necessary.
267  *
268  * @param[in] opcode      Operation code. Sending first.
269  * @param[in] length      Length of the data to send and opcode. See @ref nrf_qspi_cinstr_len_t.
270  * @param[in] p_tx_buffer Pointer to input data array.
271  *
272  * @retval NRFX_SUCCESS            If the operation was successful.
273  * @retval NRFX_ERROR_BUSY         If the driver currently handles another operation.
274  */
275 nrfx_err_t nrfx_qspi_cinstr_quick_send(uint8_t               opcode,
276                                        nrf_qspi_cinstr_len_t length,
277                                        void const *          p_tx_buffer);
278 
279 
280 void nrfx_qspi_irq_handler(void);
281 
282 /** @} */
283 
284 #ifdef __cplusplus
285 }
286 #endif
287 
288 #endif // NRFX_QSPI_H__
289