1515LOG_MODULE_REGISTER (spi_lpspi , CONFIG_SPI_LOG_LEVEL );
1616
1717#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)
1921
2022#if defined(LPSPI_RSTS ) || defined(LPSPI_CLOCKS )
2123static 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)
116118 return 0 ;
117119}
118120
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+
119271int spi_mcux_configure (const struct device * dev , const struct spi_config * spi_cfg )
120272{
121273 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
124276 bool already_configured = spi_context_configured (ctx , spi_cfg );
125277 LPSPI_Type * base = (LPSPI_Type * )DEVICE_MMIO_NAMED_GET (dev , reg_base );
126278 uint32_t word_size = SPI_WORD_SIZE_GET (spi_cfg -> operation );
127- lpspi_master_config_t master_config ;
128279 uint32_t clock_freq ;
280+ uint8_t prescaler ;
129281 int ret ;
130282
131283 /* fast path to avoid reconfigure */
@@ -141,10 +293,8 @@ int spi_mcux_configure(const struct device *dev, const struct spi_config *spi_cf
141293 return ret ;
142294 }
143295
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 ;
148298
149299 /* specific driver implementation should set up watermarks and interrupts.
150300 * 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
164314
165315 data -> ctx .config = spi_cfg ;
166316
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 );
191318
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 ;
194322 }
195323
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+
196337 return 0 ;
197338}
198339
@@ -235,7 +376,10 @@ int spi_nxp_init_common(const struct device *dev)
235376 return err ;
236377 }
237378
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 ;
239383
240384 config -> irq_config_func (dev );
241385
0 commit comments