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,182 @@ static inline int lpspi_validate_xfer_args(const struct spi_config *spi_cfg)
120
122
return 0 ;
121
123
}
122
124
125
+ static uint32_t lpspi_calc_delay (uint32_t prescaled_clock , uint16_t cycles )
126
+ {
127
+ return (uint32_t )((uint64_t )NSEC_PER_SEC * cycles / prescaled_clock );
128
+ }
129
+
130
+ static uint8_t lpspi_calc_delay_scaler (uint32_t desired_delay_ns ,
131
+ uint32_t prescaled_clock ,
132
+ /* what the base_scaler parameter is about is
133
+ * that PCSSCK and SCKPSC are +1 cycles of the
134
+ * programmed value,
135
+ * while DBT is +2 cycles of the programmed value.
136
+ * Minimum value of base_scaler should be 1.
137
+ */
138
+ uint32_t base_scaler )
139
+ {
140
+ int16_t delay_cycles = base_scaler + 255U ;
141
+
142
+ if (lpspi_calc_delay (prescaled_clock , base_scaler ) >= desired_delay_ns ) {
143
+ return 0 ;
144
+ }
145
+
146
+ /* the scaler value is how many cycles of the prescaled clock to delay for.
147
+ * We most likely want to treat the requested delay as a minimum, since it
148
+ * probably has to do with setup and hold times of some spi device.
149
+ * So this algorithm is simple linear time algorithm that approaches the
150
+ * desired value from above.
151
+ */
152
+ do {
153
+ if (lpspi_calc_delay (prescaled_clock , delay_cycles ) < desired_delay_ns ) {
154
+ break ;
155
+ }
156
+ } while (-- delay_cycles >= 0 );
157
+
158
+ /* +1 is because we decremented delay_cycles by 1 too many by the end of the loop */
159
+ return (delay_cycles + 1 ) - base_scaler ;
160
+ }
161
+
162
+ /* returns CCR mask of the bits 8-31 */
163
+ static inline uint32_t lpspi_set_delays (const struct device * dev , uint32_t prescaled_clock )
164
+ {
165
+ const struct lpspi_config * config = dev -> config ;
166
+
167
+ return LPSPI_CCR_PCSSCK (lpspi_calc_delay_scaler (config -> pcs_sck_delay ,
168
+ prescaled_clock , 1 )) |
169
+ LPSPI_CCR_SCKPCS (lpspi_calc_delay_scaler (config -> sck_pcs_delay ,
170
+ prescaled_clock , 1 )) |
171
+ LPSPI_CCR_DBT (lpspi_calc_delay_scaler (config -> transfer_delay ,
172
+ prescaled_clock , 2 ));
173
+ }
174
+
175
+ /* This is the equation for the sck frequency given a div and prescaler. */
176
+ static uint32_t lpspi_calc_sck_freq (uint32_t src_clk_hz , uint16_t sckdiv , uint8_t prescaler )
177
+ {
178
+ return (uint32_t )(src_clk_hz / (TWO_EXP (prescaler ) * (sckdiv + 2 )));
179
+ }
180
+
181
+ /* This function returns the best div for a prescaler, within the frequency bound
182
+ * of the min and max params, given a src clk freq. It tries to get as close to
183
+ * the max freq as possible without going over, with min freq as the value to beat.
184
+ */
185
+ static inline uint8_t lpspi_find_best_div_for_prescaler (uint32_t src_clk_hz ,
186
+ uint8_t prescaler ,
187
+ uint32_t min_freq ,
188
+ uint32_t max_freq )
189
+ {
190
+ uint8_t high = 255 , low = 0 , try = 255 , best = 255 ;
191
+ uint32_t new_freq = min_freq ;
192
+
193
+ do {
194
+ try = low + (high - low ) / 2 ;
195
+ new_freq = lpspi_calc_sck_freq (src_clk_hz , try , prescaler );
196
+
197
+ /* ensure that we do not exceed desired freq */
198
+ if (new_freq > max_freq ) {
199
+ low = MIN (try + 1 , high );
200
+ continue ;
201
+ } else {
202
+ high = MAX (try - 1 , low );
203
+ }
204
+
205
+ /* check if we are closer to the desired, update bests if needed */
206
+ if (new_freq >= min_freq ) {
207
+ best = try ;
208
+ min_freq = new_freq ;
209
+ }
210
+
211
+ /* if our best found is an exact match, we're done early */
212
+ if (min_freq == max_freq ) {
213
+ break ;
214
+ }
215
+ } while (low < high );
216
+
217
+ if (low == high ) {
218
+ new_freq = lpspi_calc_sck_freq (src_clk_hz , high , prescaler );
219
+ if (new_freq > min_freq && new_freq <= max_freq ) {
220
+ best = high ;
221
+ }
222
+ }
223
+
224
+ return best ;
225
+ }
226
+
227
+ /* This function configures the clock control register (CCR) for the desired frequency
228
+ * It does a binary search for the optimal CCR divider and TCR prescaler.
229
+ * The prescale_value parameter is changed to the best value of the prescaler,
230
+ * for use in setting the TCR outside this function.
231
+ * The return value is the mask of the CCR (bits 0-7) required to set SCKDIV for best result.
232
+ */
233
+ static inline uint32_t lpspi_set_sckdiv (uint32_t desired_freq ,
234
+ uint32_t clock_freq , uint8_t * prescale_value )
235
+ {
236
+ uint8_t best_prescaler = 0 , best_div = 0 ;
237
+ uint32_t best_freq = 0 ;
238
+
239
+ for (uint8_t prescaler = 0U ; prescaler < 8U ; prescaler ++ ) {
240
+ /* if maximum freq (div = 0) won't get better than what we got with
241
+ * previous prescaler, then we can fast path exit this loop.
242
+ */
243
+ if (lpspi_calc_sck_freq (clock_freq , 0 , prescaler ) < best_freq ) {
244
+ break ;
245
+ }
246
+
247
+ /* the algorithm approaches the desired freq from below intentionally,
248
+ * therefore the min is our previous best and the max is the desired.
249
+ */
250
+ uint8_t new_div = lpspi_find_best_div_for_prescaler (clock_freq , prescaler ,
251
+ best_freq , desired_freq );
252
+ uint32_t new_freq = lpspi_calc_sck_freq (clock_freq , new_div , prescaler );
253
+
254
+ if (new_freq >= best_freq && new_freq <= desired_freq ) {
255
+ best_div = new_div ;
256
+ best_freq = new_freq ;
257
+ best_prescaler = prescaler ;
258
+ }
259
+ }
260
+
261
+ * prescale_value = best_prescaler ;
262
+
263
+ return LPSPI_CCR_SCKDIV (best_div );
264
+ }
265
+
266
+ /* This function configures everything except the TCR and the clock scaler */
267
+ static void lpspi_basic_config (const struct device * dev , const struct spi_config * spi_cfg )
268
+ {
269
+ const struct lpspi_config * config = dev -> config ;
270
+ LPSPI_Type * base = (LPSPI_Type * )DEVICE_MMIO_NAMED_GET (dev , reg_base );
271
+ uint32_t pcs_control_bit = 1 << (LPSPI_CFGR1_PCSPOL_SHIFT + spi_cfg -> slave );
272
+ uint32_t cfgr1_val = 0 ;
273
+
274
+ if (spi_cfg -> operation & SPI_CS_ACTIVE_HIGH ) {
275
+ cfgr1_val |= pcs_control_bit ;
276
+ } else {
277
+ cfgr1_val &= ~pcs_control_bit ;
278
+ }
279
+
280
+ if (SPI_OP_MODE_GET (spi_cfg -> operation ) == SPI_OP_MODE_MASTER ) {
281
+ cfgr1_val |= LPSPI_CFGR1_MASTER_MASK ;
282
+ }
283
+
284
+ if (config -> tristate_output ) {
285
+ cfgr1_val |= LPSPI_CFGR1_OUTCFG_MASK ;
286
+ }
287
+
288
+ cfgr1_val |= config -> data_pin_config << LPSPI_CFGR1_PINCFG_SHIFT ;
289
+
290
+ base -> CFGR1 = cfgr1_val ;
291
+
292
+ if (IS_ENABLED (CONFIG_DEBUG )) {
293
+ /* DEBUG mode makes it so the lpspi does not keep
294
+ * running while debugger has halted the chip.
295
+ * This makes debugging spi transfers easier.
296
+ */
297
+ base -> CR |= LPSPI_CR_DBGEN_MASK ;
298
+ }
299
+ }
300
+
123
301
int spi_mcux_configure (const struct device * dev , const struct spi_config * spi_cfg )
124
302
{
125
303
const struct lpspi_config * config = dev -> config ;
@@ -128,9 +306,9 @@ int spi_mcux_configure(const struct device *dev, const struct spi_config *spi_cf
128
306
bool already_configured = spi_context_configured (ctx , spi_cfg );
129
307
LPSPI_Type * base = (LPSPI_Type * )DEVICE_MMIO_NAMED_GET (dev , reg_base );
130
308
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 ;
309
+ uint32_t clock_freq = 0 ;
310
+ uint8_t prescaler = 0 ;
311
+ int ret = 0 ;
134
312
135
313
/* fast path to avoid reconfigure */
136
314
/* TODO: S32K3 errata ERR050456 requiring module reset before every transfer,
@@ -145,10 +323,8 @@ int spi_mcux_configure(const struct device *dev, const struct spi_config *spi_cf
145
323
return ret ;
146
324
}
147
325
148
- ret = clock_control_get_rate (config -> clock_dev , config -> clock_subsys , & clock_freq );
149
- if (ret ) {
150
- return ret ;
151
- }
326
+ /* For the purpose of configuring the LPSPI, 8 is the minimum frame size for the hardware */
327
+ word_size = word_size < 8 ? 8 : word_size ;
152
328
153
329
/* specific driver implementation should set up watermarks and interrupts.
154
330
* we reset them here to avoid any unexpected events during configuring.
@@ -168,35 +344,34 @@ int spi_mcux_configure(const struct device *dev, const struct spi_config *spi_cf
168
344
169
345
data -> ctx .config = spi_cfg ;
170
346
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 );
347
+ lpspi_basic_config (dev , spi_cfg );
195
348
196
- if (IS_ENABLED (CONFIG_DEBUG )) {
197
- base -> CR |= LPSPI_CR_DBGEN_MASK ;
349
+ ret = clock_control_get_rate (config -> clock_dev , config -> clock_subsys , & clock_freq );
350
+ if (ret ) {
351
+ return ret ;
198
352
}
199
353
354
+ if (SPI_OP_MODE_GET (spi_cfg -> operation ) == SPI_OP_MODE_MASTER ) {
355
+ uint32_t ccr = 0 ;
356
+
357
+ /* sckdiv algorithm must run *before* delays are set in order to know prescaler */
358
+ ccr |= lpspi_set_sckdiv (spi_cfg -> frequency , clock_freq , & prescaler );
359
+ ccr |= lpspi_set_delays (dev , clock_freq / TWO_EXP (prescaler ));
360
+
361
+ /* note that not all bits of the register are readable on some platform,
362
+ * that's why we update it on one write
363
+ */
364
+ base -> CCR = ccr ;
365
+ }
366
+
367
+ base -> CR |= LPSPI_CR_MEN_MASK ;
368
+
369
+ base -> TCR = LPSPI_TCR_CPOL (!!(spi_cfg -> operation & SPI_MODE_CPOL )) |
370
+ LPSPI_TCR_CPHA (!!(spi_cfg -> operation & SPI_MODE_CPHA )) |
371
+ LPSPI_TCR_LSBF (!!(spi_cfg -> operation & SPI_TRANSFER_LSB )) |
372
+ LPSPI_TCR_FRAMESZ (word_size - 1 ) |
373
+ LPSPI_TCR_PRESCALE (prescaler ) | LPSPI_TCR_PCS (spi_cfg -> slave );
374
+
200
375
return lpspi_wait_tx_fifo_empty (dev );
201
376
}
202
377
@@ -239,7 +414,10 @@ int spi_nxp_init_common(const struct device *dev)
239
414
return err ;
240
415
}
241
416
242
- LPSPI_Reset (base );
417
+ /* Full software reset */
418
+ base -> CR |= LPSPI_CR_RST_MASK ;
419
+ base -> CR |= LPSPI_CR_RRF_MASK | LPSPI_CR_RTF_MASK ;
420
+ base -> CR = 0x00U ;
243
421
244
422
config -> irq_config_func (dev );
245
423
0 commit comments