@@ -96,68 +96,105 @@ static inline void lpspi_handle_rx_irq(const struct device *dev)
9696 }
9797}
9898
99- static inline uint32_t lpspi_next_tx_word (const struct device * dev , int offset )
99+ /* constructs the next word from the buffer */
100+ static inline uint32_t lpspi_next_tx_word (const struct device * dev , const uint8_t * buf ,
101+ int offset , size_t max_bytes )
100102{
101- struct lpspi_data * data = dev -> data ;
102- struct lpspi_driver_data * lpspi_data = (struct lpspi_driver_data * )data -> driver_data ;
103- struct spi_context * ctx = & data -> ctx ;
104- const uint8_t * byte = ctx -> tx_buf + offset ;
105- uint32_t num_bytes = MIN (lpspi_data -> word_size_bytes , ctx -> tx_len );
103+ const uint8_t * byte = buf + offset ;
106104 uint32_t next_word = 0 ;
107105
108- for (uint8_t i = 0 ; i < num_bytes ; i ++ ) {
106+ for (uint8_t i = 0 ; i < max_bytes ; i ++ ) {
109107 next_word |= byte [i ] << (BITS_PER_BYTE * i );
110108 }
111109
112110 return next_word ;
113111}
114112
115- static inline void lpspi_fill_tx_fifo (const struct device * dev )
113+ /* fills the TX fifo with specified amount of data from the specified buffer */
114+ static inline void lpspi_fill_tx_fifo (const struct device * dev , const uint8_t * buf ,
115+ size_t buf_len , size_t fill_len )
116116{
117117 LPSPI_Type * base = (LPSPI_Type * )DEVICE_MMIO_NAMED_GET (dev , reg_base );
118118 struct lpspi_data * data = dev -> data ;
119119 struct lpspi_driver_data * lpspi_data = (struct lpspi_driver_data * )data -> driver_data ;
120- size_t bytes_in_xfer = lpspi_data -> fill_len * lpspi_data -> word_size_bytes ;
121- size_t offset ;
122-
123- for (offset = 0 ; offset < bytes_in_xfer ; offset += lpspi_data -> word_size_bytes ) {
124- base -> TDR = lpspi_next_tx_word (dev , offset );
120+ uint8_t word_size = lpspi_data -> word_size_bytes ;
121+ size_t buf_remaining_bytes = buf_len * word_size ;
122+ size_t offset = 0 ;
123+ uint32_t next_word ;
124+ uint32_t next_word_bytes ;
125+
126+ for (int word_count = 0 ; word_count < fill_len ; word_count ++ ) {
127+ next_word_bytes = MIN (word_size , buf_remaining_bytes );
128+ next_word = lpspi_next_tx_word (dev , buf , offset , next_word_bytes );
129+ base -> TDR = next_word ;
130+ offset += word_size ;
131+ buf_remaining_bytes -= word_size ;
125132 }
126133
127134 LOG_DBG ("Filled TX FIFO to %d words (%d bytes)" , lpspi_data -> fill_len , offset );
128135}
129136
130- static void lpspi_fill_tx_fifo_nop (const struct device * dev )
137+ /* just fills TX fifo with the specified amount of NOPS */
138+ static void lpspi_fill_tx_fifo_nop (const struct device * dev , size_t fill_len )
131139{
132140 LPSPI_Type * base = (LPSPI_Type * )DEVICE_MMIO_NAMED_GET (dev , reg_base );
133- struct lpspi_data * data = dev -> data ;
134- struct lpspi_driver_data * lpspi_data = (struct lpspi_driver_data * )data -> driver_data ;
135141
136- for (int i = 0 ; i < lpspi_data -> fill_len ; i ++ ) {
142+ for (int i = 0 ; i < fill_len ; i ++ ) {
137143 base -> TDR = 0 ;
138144 }
139145
140- LOG_DBG ("Filled TX fifo with %d NOPs" , lpspi_data -> fill_len );
146+ LOG_DBG ("Filled TX fifo with %d NOPs" , fill_len );
141147}
142148
149+ /* handles refilling the TX fifo from empty */
143150static void lpspi_next_tx_fill (const struct device * dev )
144151{
145152 const struct lpspi_config * config = dev -> config ;
146153 struct lpspi_data * data = dev -> data ;
147154 struct lpspi_driver_data * lpspi_data = (struct lpspi_driver_data * )data -> driver_data ;
148155 struct spi_context * ctx = & data -> ctx ;
149- size_t max_chunk ;
156+ size_t fill_len ;
157+ size_t actual_filled = 0 ;
150158
151159 /* Convert bytes to words for this xfer */
152- max_chunk = DIV_ROUND_UP (ctx -> tx_len , lpspi_data -> word_size_bytes );
153- max_chunk = MIN (max_chunk , config -> tx_fifo_size );
154- lpspi_data -> fill_len = max_chunk ;
155-
156- if (spi_context_tx_buf_on (ctx )) {
157- lpspi_fill_tx_fifo (dev );
158- } else {
159- lpspi_fill_tx_fifo_nop (dev );
160+ fill_len = DIV_ROUND_UP (spi_context_tx_len_left (ctx ), lpspi_data -> word_size_bytes );
161+ fill_len = MIN (fill_len , config -> tx_fifo_size );
162+
163+ const struct spi_buf * current_buf = ctx -> current_tx ;
164+ const uint8_t * cur_buf_pos = ctx -> tx_buf ;
165+ size_t cur_buf_len_left = ctx -> tx_len ;
166+ size_t bufs_left = ctx -> tx_count ;
167+
168+ while (fill_len > 0 ) {
169+ size_t next_buf_fill = MIN (cur_buf_len_left , fill_len );
170+
171+ if (cur_buf_pos == NULL ) {
172+ lpspi_fill_tx_fifo_nop (dev , next_buf_fill );
173+ } else {
174+ lpspi_fill_tx_fifo (dev , cur_buf_pos ,
175+ current_buf -> len , next_buf_fill );
176+ }
177+
178+ fill_len -= next_buf_fill ;
179+ cur_buf_pos += next_buf_fill ;
180+
181+ /* in the case where we just filled as much as we could from the current buffer,
182+ * this logic while wrong should have no effect, since fill_len will be 0,
183+ * so I choose not to make the code extra complex
184+ */
185+ bufs_left -- ;
186+ if (bufs_left > 0 ) {
187+ current_buf += 1 ;
188+ cur_buf_len_left = current_buf -> len ;
189+ cur_buf_pos = current_buf -> buf ;
190+ } else {
191+ fill_len = 0 ;
192+ }
193+
194+ actual_filled += next_buf_fill ;
160195 }
196+
197+ lpspi_data -> fill_len = actual_filled ;
161198}
162199
163200static inline void lpspi_handle_tx_irq (const struct device * dev )
@@ -167,7 +204,12 @@ static inline void lpspi_handle_tx_irq(const struct device *dev)
167204 struct lpspi_driver_data * lpspi_data = (struct lpspi_driver_data * )data -> driver_data ;
168205 struct spi_context * ctx = & data -> ctx ;
169206
170- spi_context_update_tx (ctx , lpspi_data -> word_size_bytes , lpspi_data -> fill_len );
207+ while (spi_context_tx_on (ctx ) && lpspi_data -> fill_len > 0 ) {
208+ size_t this_buf_words_sent = MIN (lpspi_data -> fill_len , ctx -> tx_len );
209+
210+ spi_context_update_tx (ctx , lpspi_data -> word_size_bytes , this_buf_words_sent );
211+ lpspi_data -> fill_len -= this_buf_words_sent ;
212+ }
171213
172214 base -> SR = LPSPI_SR_TDF_MASK ;
173215
@@ -206,10 +248,11 @@ static void lpspi_isr(const struct device *dev)
206248 size_t max_fill = MIN (expected_rx_left , config -> rx_fifo_size );
207249 size_t tx_current_fifo_len = tx_fifo_cur_len (base );
208250
209- lpspi_data -> fill_len = tx_current_fifo_len < ctx -> rx_len ?
251+ size_t fill_len = tx_current_fifo_len < ctx -> rx_len ?
210252 max_fill - tx_current_fifo_len : 0 ;
211253
212- lpspi_fill_tx_fifo_nop (dev );
254+ lpspi_fill_tx_fifo_nop (dev , fill_len );
255+ lpspi_data -> fill_len = fill_len ;
213256 }
214257
215258 if (spi_context_rx_len_left (ctx ) == 1 ) {
0 commit comments