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