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 ;
@@ -116,6 +118,156 @@ static inline int lpspi_validate_xfer_args(const struct spi_config *spi_cfg)
116
118
return 0 ;
117
119
}
118
120
121
+ static uint8_t lpspi_calc_delay (uint32_t desired_delay_ns , uint32_t best_delay_ns ,
122
+ uint32_t prescaled_clock , uint32_t additional_scaler )
123
+ {
124
+ uint64_t real_delay = NSEC_PER_SEC / prescaled_clock ;
125
+ uint8_t best_scaler = 0 , scaler = 0 ;
126
+ uint32_t diff , min_diff = 0xFFFFFFFF ;
127
+
128
+ while (scaler < 256 && min_diff != 0 ) {
129
+ real_delay *= ((uint64_t )scaler + 1 + (uint64_t )additional_scaler );
130
+
131
+ /* Delay must not be less than desired */
132
+ if (real_delay >= desired_delay_ns ) {
133
+ diff = (uint32_t )(real_delay - (uint64_t )desired_delay_ns );
134
+ if (min_diff > diff ) {
135
+ /* a better match found */
136
+ min_diff = diff ;
137
+ best_scaler = scaler ;
138
+ }
139
+ }
140
+
141
+ scaler ++ ;
142
+ }
143
+
144
+ return best_scaler ;
145
+ }
146
+
147
+ static inline void lpspi_set_delays (const struct device * dev , uint32_t prescaled_clock )
148
+ {
149
+ LPSPI_Type * base = (LPSPI_Type * )DEVICE_MMIO_NAMED_GET (dev , reg_base );
150
+ uint64_t minimum_delay_ns = NSEC_PER_SEC / prescaled_clock ;
151
+ const struct lpspi_config * config = dev -> config ;
152
+ uint32_t ccr = base -> CCR ;
153
+
154
+ ccr &= ~(LPSPI_CCR_PCSSCK_MASK | LPSPI_CCR_SCKPCS_MASK | LPSPI_CCR_DBT_MASK );
155
+
156
+ if (config -> pcs_sck_delay <= minimum_delay_ns ) {
157
+ ccr |= LPSPI_CCR_PCSSCK (lpspi_calc_delay (config -> pcs_sck_delay ,
158
+ minimum_delay_ns * 256 ,
159
+ prescaled_clock , 0 ));
160
+ }
161
+
162
+ if (config -> sck_pcs_delay <= minimum_delay_ns ) {
163
+ ccr |= LPSPI_CCR_SCKPCS (lpspi_calc_delay (config -> sck_pcs_delay ,
164
+ minimum_delay_ns * 256 ,
165
+ prescaled_clock , 0 ));
166
+ }
167
+
168
+ if (config -> transfer_delay <= (2 * minimum_delay_ns )) {
169
+ ccr |= LPSPI_CCR_DBT (lpspi_calc_delay (config -> transfer_delay ,
170
+ minimum_delay_ns * 257 ,
171
+ prescaled_clock , 1 ));
172
+ }
173
+
174
+ base -> CCR = ccr ;
175
+ }
176
+
177
+
178
+ /* This function configures the clock control register (CCR) for the desired frequency
179
+ * It does a binary search for the optimal CCR divider and TCR prescaler.
180
+ * The return value is the actual best frequency found, and the prescale_value parameter
181
+ * is changed to the best value of the prescaler, for use in setting the TCR outside this function.
182
+ */
183
+ static inline uint32_t lpspi_set_sckdiv (LPSPI_Type * base , uint32_t desired_freq ,
184
+ uint32_t clock_freq , uint8_t * prescale_value )
185
+ {
186
+ uint8_t best_prescaler = 0 , best_div = 0 ;
187
+ uint32_t best_freq = 0 ;
188
+
189
+ for (uint8_t prescaler = 0U ; prescaler < 8U ; prescaler ++ ) {
190
+ uint8_t high = 255 , low = 0 , div = 255 ;
191
+ uint32_t real_freq = 0 ;
192
+
193
+ /* maximum freq won't get better than what we got with previous prescaler */
194
+ if (clock_freq / (TWO_EXP (prescaler ) * 2 ) < best_freq ) {
195
+ goto done ;
196
+ }
197
+
198
+ while (div > 0 ) {
199
+ div = low + (high - low ) / 2 ;
200
+ real_freq = (clock_freq / (TWO_EXP (prescaler ) * (div + 2 )));
201
+
202
+ /* ensure that we do not exceed desired freq */
203
+ if (real_freq > desired_freq ) {
204
+ low = div + 1 ;
205
+ continue ;
206
+ } else {
207
+ high = div - 1 ;
208
+ }
209
+
210
+ /* check if we are closer to the desired */
211
+ if (real_freq >= best_freq ) {
212
+ best_prescaler = prescaler ;
213
+ best_div = div ;
214
+ best_freq = real_freq ;
215
+ }
216
+
217
+ /* if our best found is a match, we're done */
218
+ if (best_freq == desired_freq ) {
219
+ goto done ;
220
+ }
221
+ }
222
+ }
223
+
224
+ done :
225
+ uint32_t ccr_val = base -> CCR & ~LPSPI_CCR_SCKDIV_MASK ;
226
+
227
+ ccr_val |= LPSPI_CCR_SCKDIV (best_div );
228
+
229
+ base -> CCR = ccr_val ;
230
+
231
+ * prescale_value = best_prescaler ;
232
+
233
+ return best_freq ;
234
+ }
235
+
236
+ /* This function configures everything except the TCR and the clock scaler */
237
+ static void lpspi_basic_config (const struct device * dev , const struct spi_config * spi_cfg )
238
+ {
239
+ const struct lpspi_config * config = dev -> config ;
240
+ LPSPI_Type * base = (LPSPI_Type * )DEVICE_MMIO_NAMED_GET (dev , reg_base );
241
+ uint32_t pcs_control_bit = 1 << (LPSPI_CFGR1_PCSPOL_SHIFT + spi_cfg -> slave );
242
+ uint32_t cfgr1_val = 0 ;
243
+
244
+ if (spi_cfg -> operation & SPI_CS_ACTIVE_HIGH ) {
245
+ cfgr1_val |= pcs_control_bit ;
246
+ } else {
247
+ cfgr1_val &= ~pcs_control_bit ;
248
+ }
249
+
250
+ if (SPI_OP_MODE_GET (spi_cfg -> operation ) == SPI_OP_MODE_MASTER ) {
251
+ cfgr1_val |= LPSPI_CFGR1_MASTER_MASK ;
252
+ }
253
+
254
+ if (config -> tristate_output ) {
255
+ cfgr1_val |= LPSPI_CFGR1_OUTCFG_MASK ;
256
+ }
257
+
258
+ cfgr1_val |= config -> data_pin_config << LPSPI_CFGR1_PINCFG_SHIFT ;
259
+
260
+ base -> CFGR1 = cfgr1_val ;
261
+
262
+ if (IS_ENABLED (CONFIG_DEBUG )) {
263
+ /* DEBUG mode makes it so the lpspi does not keep
264
+ * running while debugger has halted the chip.
265
+ * This makes debugging spi transfers easier.
266
+ */
267
+ base -> CR |= LPSPI_CR_DBGEN_MASK ;
268
+ }
269
+ }
270
+
119
271
int spi_mcux_configure (const struct device * dev , const struct spi_config * spi_cfg )
120
272
{
121
273
const struct lpspi_config * config = dev -> config ;
@@ -124,8 +276,8 @@ int spi_mcux_configure(const struct device *dev, const struct spi_config *spi_cf
124
276
bool already_configured = spi_context_configured (ctx , spi_cfg );
125
277
LPSPI_Type * base = (LPSPI_Type * )DEVICE_MMIO_NAMED_GET (dev , reg_base );
126
278
uint32_t word_size = SPI_WORD_SIZE_GET (spi_cfg -> operation );
127
- lpspi_master_config_t master_config ;
128
279
uint32_t clock_freq ;
280
+ uint8_t prescaler ;
129
281
int ret ;
130
282
131
283
/* fast path to avoid reconfigure */
@@ -141,10 +293,8 @@ int spi_mcux_configure(const struct device *dev, const struct spi_config *spi_cf
141
293
return ret ;
142
294
}
143
295
144
- ret = clock_control_get_rate (config -> clock_dev , config -> clock_subsys , & clock_freq );
145
- if (ret ) {
146
- return ret ;
147
- }
296
+ /* For the purpose of configuring the LPSPI, 8 is the minimum frame size for the hardware */
297
+ word_size = word_size < 8 ? 8 : word_size ;
148
298
149
299
/* specific driver implementation should set up watermarks and interrupts.
150
300
* we reset them here to avoid any unexpected events during configuring.
@@ -164,35 +314,26 @@ int spi_mcux_configure(const struct device *dev, const struct spi_config *spi_cf
164
314
165
315
data -> ctx .config = spi_cfg ;
166
316
167
- LPSPI_MasterGetDefaultConfig (& master_config );
168
-
169
- master_config .bitsPerFrame = word_size < 8 ? 8 : word_size ; /* minimum FRAMSZ is 8 */
170
- master_config .cpol = (SPI_MODE_GET (spi_cfg -> operation ) & SPI_MODE_CPOL )
171
- ? kLPSPI_ClockPolarityActiveLow
172
- : kLPSPI_ClockPolarityActiveHigh ;
173
- master_config .cpha = (SPI_MODE_GET (spi_cfg -> operation ) & SPI_MODE_CPHA )
174
- ? kLPSPI_ClockPhaseSecondEdge
175
- : kLPSPI_ClockPhaseFirstEdge ;
176
- master_config .direction =
177
- (spi_cfg -> operation & SPI_TRANSFER_LSB ) ? kLPSPI_LsbFirst : kLPSPI_MsbFirst ;
178
- master_config .baudRate = spi_cfg -> frequency ;
179
- master_config .pcsToSckDelayInNanoSec = config -> pcs_sck_delay ;
180
- master_config .lastSckToPcsDelayInNanoSec = config -> sck_pcs_delay ;
181
- master_config .betweenTransferDelayInNanoSec = config -> transfer_delay ;
182
- master_config .whichPcs = spi_cfg -> slave + kLPSPI_Pcs0 ;
183
- master_config .pcsActiveHighOrLow = (spi_cfg -> operation & SPI_CS_ACTIVE_HIGH )
184
- ? kLPSPI_PcsActiveHigh : kLPSPI_PcsActiveLow ;
185
- master_config .pinCfg = config -> data_pin_config ;
186
- master_config .dataOutConfig = config -> tristate_output ? kLpspiDataOutTristate :
187
- kLpspiDataOutRetained ;
188
-
189
- LPSPI_MasterInit (base , & master_config , clock_freq );
190
- LPSPI_SetDummyData (base , 0 );
317
+ lpspi_basic_config (dev , spi_cfg );
191
318
192
- if (IS_ENABLED (CONFIG_DEBUG )) {
193
- base -> CR |= LPSPI_CR_DBGEN_MASK ;
319
+ ret = clock_control_get_rate (config -> clock_dev , config -> clock_subsys , & clock_freq );
320
+ if (ret ) {
321
+ return ret ;
194
322
}
195
323
324
+ lpspi_set_sckdiv (base , spi_cfg -> frequency , clock_freq , & prescaler );
325
+ lpspi_set_delays (dev , clock_freq / TWO_EXP (prescaler ));
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 (SPI_WORD_SIZE_GET (spi_cfg -> operation )) |
333
+ LPSPI_TCR_PRESCALE (prescaler ) | LPSPI_TCR_PCS (spi_cfg -> slave );
334
+
335
+ lpspi_wait_tx_fifo_empty (dev );
336
+
196
337
return 0 ;
197
338
}
198
339
@@ -235,7 +376,10 @@ int spi_nxp_init_common(const struct device *dev)
235
376
return err ;
236
377
}
237
378
238
- LPSPI_Reset (base );
379
+ /* Full software reset */
380
+ base -> CR |= LPSPI_CR_RST_MASK ;
381
+ base -> CR |= LPSPI_CR_RRF_MASK | LPSPI_CR_RTF_MASK ;
382
+ base -> CR = 0x00U ;
239
383
240
384
config -> irq_config_func (dev );
241
385
0 commit comments