15
15
LOG_MODULE_REGISTER (spi_lpspi , CONFIG_SPI_LOG_LEVEL );
16
16
17
17
#include "spi_nxp_lpspi_priv.h"
18
- #include <fsl_lpspi.h>
18
+
19
+ /* simple macro for readability of the equations used in the clock configuring */
20
+ #define TWO_EXP (power ) BIT(power)
19
21
20
22
#if defined(LPSPI_RSTS ) || defined(LPSPI_CLOCKS )
21
23
static LPSPI_Type * const lpspi_bases [] = LPSPI_BASE_PTRS ;
@@ -120,6 +122,142 @@ static inline int lpspi_validate_xfer_args(const struct spi_config *spi_cfg)
120
122
return 0 ;
121
123
}
122
124
125
+ static uint8_t lpspi_calc_delay_scaler (uint32_t desired_delay_ns ,
126
+ uint32_t prescaled_clock ,
127
+ uint32_t min_cycles )
128
+ {
129
+ uint64_t delay_cycles ;
130
+
131
+ /* calculates the number of functional clock cycles needed to achieve delay */
132
+ delay_cycles = (uint64_t )prescaled_clock * desired_delay_ns ;
133
+ delay_cycles = DIV_ROUND_UP (delay_cycles , NSEC_PER_SEC );
134
+
135
+ /* what the min_cycles parameter is about is that
136
+ * PCSSCK and SCKPSC are +1 cycles of the programmed value,
137
+ * while DBT is +2 cycles of the programmed value.
138
+ * So this calculates the value to program to the register.
139
+ */
140
+ delay_cycles -= min_cycles ;
141
+
142
+ /* Don't overflow */
143
+ delay_cycles = MIN (delay_cycles , UINT8_MAX );
144
+
145
+ return (uint8_t )delay_cycles ;
146
+ }
147
+
148
+ /* returns CCR mask of the bits 8-31 */
149
+ static inline uint32_t lpspi_set_delays (const struct device * dev , uint32_t prescaled_clock )
150
+ {
151
+ const struct lpspi_config * config = dev -> config ;
152
+
153
+ return LPSPI_CCR_PCSSCK (lpspi_calc_delay_scaler (config -> pcs_sck_delay ,
154
+ prescaled_clock , 1 )) |
155
+ LPSPI_CCR_SCKPCS (lpspi_calc_delay_scaler (config -> sck_pcs_delay ,
156
+ prescaled_clock , 1 )) |
157
+ LPSPI_CCR_DBT (lpspi_calc_delay_scaler (config -> transfer_delay ,
158
+ prescaled_clock , 2 ));
159
+ }
160
+
161
+ /* This is the equation for the sck frequency given a div and prescaler. */
162
+ static uint32_t lpspi_calc_sck_freq (uint32_t src_clk_hz , uint16_t sckdiv , uint8_t prescaler )
163
+ {
164
+ return (uint32_t )(src_clk_hz / (TWO_EXP (prescaler ) * (sckdiv + 2 )));
165
+ }
166
+
167
+ static inline uint8_t lpspi_calc_best_div_for_prescaler (uint32_t src_clk_hz ,
168
+ uint8_t prescaler ,
169
+ uint32_t req_freq )
170
+ {
171
+ uint64_t prescaled_req_freq = TWO_EXP (prescaler ) * req_freq ;
172
+ uint64_t ratio ;
173
+
174
+ if (prescaled_req_freq == 0 ) {
175
+ ratio = UINT8_MAX + 2 ;
176
+ } else {
177
+ ratio = DIV_ROUND_UP (src_clk_hz , prescaled_req_freq );
178
+ }
179
+
180
+ ratio = MAX (ratio , 2 );
181
+ ratio -= 2 ;
182
+ ratio = MIN (ratio , UINT8_MAX );
183
+
184
+ return (uint8_t )ratio ;
185
+ }
186
+
187
+ /* This function configures the clock control register (CCR) for the desired frequency
188
+ * It does a binary search for the optimal CCR divider and TCR prescaler.
189
+ * The prescale_value parameter is changed to the best value of the prescaler,
190
+ * for use in setting the TCR outside this function.
191
+ * The return value is the mask of the CCR (bits 0-7) required to set SCKDIV for best result.
192
+ */
193
+ static inline uint32_t lpspi_set_sckdiv (uint32_t desired_freq ,
194
+ uint32_t clock_freq , uint8_t * prescale_value )
195
+ {
196
+ uint8_t best_prescaler = 0 , best_div = 0 ;
197
+ uint32_t best_freq = 0 ;
198
+
199
+ for (int8_t prescaler = 7U ; prescaler >= 0 ; prescaler -- ) {
200
+ /* if maximum freq (div = 0) won't get better than what we got with
201
+ * previous prescaler, then we can fast path exit this loop.
202
+ */
203
+ if (lpspi_calc_sck_freq (clock_freq , 0 , prescaler ) < best_freq ) {
204
+ break ;
205
+ }
206
+
207
+ /* the algorithm approaches the desired freq from below intentionally,
208
+ * therefore the min is our previous best and the max is the desired.
209
+ */
210
+ uint8_t new_div = lpspi_calc_best_div_for_prescaler (clock_freq , prescaler ,
211
+ desired_freq );
212
+ uint32_t new_freq = lpspi_calc_sck_freq (clock_freq , new_div , prescaler );
213
+
214
+ if (new_freq >= best_freq && new_freq <= desired_freq ) {
215
+ best_div = new_div ;
216
+ best_freq = new_freq ;
217
+ best_prescaler = prescaler ;
218
+ }
219
+ }
220
+
221
+ * prescale_value = best_prescaler ;
222
+
223
+ return LPSPI_CCR_SCKDIV (best_div );
224
+ }
225
+
226
+ /* This function configures everything except the TCR and the clock scaler */
227
+ static void lpspi_basic_config (const struct device * dev , const struct spi_config * spi_cfg )
228
+ {
229
+ const struct lpspi_config * config = dev -> config ;
230
+ LPSPI_Type * base = (LPSPI_Type * )DEVICE_MMIO_NAMED_GET (dev , reg_base );
231
+ uint32_t pcs_control_bit = 1 << (LPSPI_CFGR1_PCSPOL_SHIFT + spi_cfg -> slave );
232
+ uint32_t cfgr1_val = 0 ;
233
+
234
+ if (spi_cfg -> operation & SPI_CS_ACTIVE_HIGH ) {
235
+ cfgr1_val |= pcs_control_bit ;
236
+ } else {
237
+ cfgr1_val &= ~pcs_control_bit ;
238
+ }
239
+
240
+ if (SPI_OP_MODE_GET (spi_cfg -> operation ) == SPI_OP_MODE_MASTER ) {
241
+ cfgr1_val |= LPSPI_CFGR1_MASTER_MASK ;
242
+ }
243
+
244
+ if (config -> tristate_output ) {
245
+ cfgr1_val |= LPSPI_CFGR1_OUTCFG_MASK ;
246
+ }
247
+
248
+ cfgr1_val |= config -> data_pin_config << LPSPI_CFGR1_PINCFG_SHIFT ;
249
+
250
+ base -> CFGR1 = cfgr1_val ;
251
+
252
+ if (IS_ENABLED (CONFIG_DEBUG )) {
253
+ /* DEBUG mode makes it so the lpspi does not keep
254
+ * running while debugger has halted the chip.
255
+ * This makes debugging spi transfers easier.
256
+ */
257
+ base -> CR |= LPSPI_CR_DBGEN_MASK ;
258
+ }
259
+ }
260
+
123
261
int spi_mcux_configure (const struct device * dev , const struct spi_config * spi_cfg )
124
262
{
125
263
const struct lpspi_config * config = dev -> config ;
@@ -128,9 +266,9 @@ int spi_mcux_configure(const struct device *dev, const struct spi_config *spi_cf
128
266
bool already_configured = spi_context_configured (ctx , spi_cfg );
129
267
LPSPI_Type * base = (LPSPI_Type * )DEVICE_MMIO_NAMED_GET (dev , reg_base );
130
268
uint32_t word_size = SPI_WORD_SIZE_GET (spi_cfg -> operation );
131
- lpspi_master_config_t master_config ;
132
- uint32_t clock_freq ;
133
- int ret ;
269
+ uint32_t clock_freq = 0 ;
270
+ uint8_t prescaler = 0 ;
271
+ int ret = 0 ;
134
272
135
273
/* fast path to avoid reconfigure */
136
274
/* TODO: S32K3 errata ERR050456 requiring module reset before every transfer,
@@ -145,10 +283,8 @@ int spi_mcux_configure(const struct device *dev, const struct spi_config *spi_cf
145
283
return ret ;
146
284
}
147
285
148
- ret = clock_control_get_rate (config -> clock_dev , config -> clock_subsys , & clock_freq );
149
- if (ret ) {
150
- return ret ;
151
- }
286
+ /* For the purpose of configuring the LPSPI, 8 is the minimum frame size for the hardware */
287
+ word_size = MAX (word_size , 8 );
152
288
153
289
/* specific driver implementation should set up watermarks and interrupts.
154
290
* we reset them here to avoid any unexpected events during configuring.
@@ -168,35 +304,34 @@ int spi_mcux_configure(const struct device *dev, const struct spi_config *spi_cf
168
304
169
305
data -> ctx .config = spi_cfg ;
170
306
171
- LPSPI_MasterGetDefaultConfig (& master_config );
172
-
173
- master_config .bitsPerFrame = word_size < 8 ? 8 : word_size ; /* minimum FRAMSZ is 8 */
174
- master_config .cpol = (SPI_MODE_GET (spi_cfg -> operation ) & SPI_MODE_CPOL )
175
- ? kLPSPI_ClockPolarityActiveLow
176
- : kLPSPI_ClockPolarityActiveHigh ;
177
- master_config .cpha = (SPI_MODE_GET (spi_cfg -> operation ) & SPI_MODE_CPHA )
178
- ? kLPSPI_ClockPhaseSecondEdge
179
- : kLPSPI_ClockPhaseFirstEdge ;
180
- master_config .direction =
181
- (spi_cfg -> operation & SPI_TRANSFER_LSB ) ? kLPSPI_LsbFirst : kLPSPI_MsbFirst ;
182
- master_config .baudRate = spi_cfg -> frequency ;
183
- master_config .pcsToSckDelayInNanoSec = config -> pcs_sck_delay ;
184
- master_config .lastSckToPcsDelayInNanoSec = config -> sck_pcs_delay ;
185
- master_config .betweenTransferDelayInNanoSec = config -> transfer_delay ;
186
- master_config .whichPcs = spi_cfg -> slave + kLPSPI_Pcs0 ;
187
- master_config .pcsActiveHighOrLow = (spi_cfg -> operation & SPI_CS_ACTIVE_HIGH )
188
- ? kLPSPI_PcsActiveHigh : kLPSPI_PcsActiveLow ;
189
- master_config .pinCfg = config -> data_pin_config ;
190
- master_config .dataOutConfig = config -> tristate_output ? kLpspiDataOutTristate :
191
- kLpspiDataOutRetained ;
192
-
193
- LPSPI_MasterInit (base , & master_config , clock_freq );
194
- LPSPI_SetDummyData (base , 0 );
307
+ lpspi_basic_config (dev , spi_cfg );
195
308
196
- if (IS_ENABLED (CONFIG_DEBUG )) {
197
- base -> CR |= LPSPI_CR_DBGEN_MASK ;
309
+ ret = clock_control_get_rate (config -> clock_dev , config -> clock_subsys , & clock_freq );
310
+ if (ret ) {
311
+ return ret ;
198
312
}
199
313
314
+ if (SPI_OP_MODE_GET (spi_cfg -> operation ) == SPI_OP_MODE_MASTER ) {
315
+ uint32_t ccr = 0 ;
316
+
317
+ /* sckdiv algorithm must run *before* delays are set in order to know prescaler */
318
+ ccr |= lpspi_set_sckdiv (spi_cfg -> frequency , clock_freq , & prescaler );
319
+ ccr |= lpspi_set_delays (dev , clock_freq / TWO_EXP (prescaler ));
320
+
321
+ /* note that not all bits of the register are readable on some platform,
322
+ * that's why we update it on one write
323
+ */
324
+ base -> CCR = ccr ;
325
+ }
326
+
327
+ base -> CR |= LPSPI_CR_MEN_MASK ;
328
+
329
+ base -> TCR = LPSPI_TCR_CPOL (!!(spi_cfg -> operation & SPI_MODE_CPOL )) |
330
+ LPSPI_TCR_CPHA (!!(spi_cfg -> operation & SPI_MODE_CPHA )) |
331
+ LPSPI_TCR_LSBF (!!(spi_cfg -> operation & SPI_TRANSFER_LSB )) |
332
+ LPSPI_TCR_FRAMESZ (word_size - 1 ) |
333
+ LPSPI_TCR_PRESCALE (prescaler ) | LPSPI_TCR_PCS (spi_cfg -> slave );
334
+
200
335
return lpspi_wait_tx_fifo_empty (dev );
201
336
}
202
337
@@ -239,7 +374,10 @@ int spi_nxp_init_common(const struct device *dev)
239
374
return err ;
240
375
}
241
376
242
- LPSPI_Reset (base );
377
+ /* Full software reset */
378
+ base -> CR |= LPSPI_CR_RST_MASK ;
379
+ base -> CR |= LPSPI_CR_RRF_MASK | LPSPI_CR_RTF_MASK ;
380
+ base -> CR = 0x00U ;
243
381
244
382
config -> irq_config_func (dev );
245
383
0 commit comments