1 /*
2 * Copyright (c) 2019 Christian Taedcke <hacking@taedcke.com>
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT silabs_gecko_spi_usart
8
9 #define LOG_LEVEL CONFIG_SPI_LOG_LEVEL
10 #include <zephyr/logging/log.h>
11 LOG_MODULE_REGISTER(spi_gecko);
12 #include "spi_context.h"
13
14 #include <zephyr/sys/sys_io.h>
15 #include <zephyr/device.h>
16 #include <zephyr/drivers/spi.h>
17 #include <soc.h>
18
19 #include "em_cmu.h"
20 #include "em_usart.h"
21
22 #include <stdbool.h>
23
24 #ifdef CONFIG_PINCTRL
25 #include <zephyr/drivers/pinctrl.h>
26 #else
27 #ifndef CONFIG_SOC_GECKO_HAS_INDIVIDUAL_PIN_LOCATION
28 #error "Individual pin location support is required"
29 #endif
30 #endif /* CONFIG_PINCTRL */
31
32 #if DT_NODE_HAS_PROP(n, peripheral_id)
33 #define CLOCK_USART(id) _CONCAT(cmuClock_USART, id)
34 #define GET_GECKO_USART_CLOCK(n) CLOCK_USART(DT_INST_PROP(n, peripheral_id))
35 #else
36 #if (USART_COUNT == 1)
37 #define CLOCK_USART(ref) (((ref) == USART0) ? cmuClock_USART0 \
38 : -1)
39 #elif (USART_COUNT == 2)
40 #define CLOCK_USART(ref) (((ref) == USART0) ? cmuClock_USART0 \
41 : ((ref) == USART1) ? cmuClock_USART1 \
42 : -1)
43 #elif (USART_COUNT == 3)
44 #define CLOCK_USART(ref) (((ref) == USART0) ? cmuClock_USART0 \
45 : ((ref) == USART1) ? cmuClock_USART1 \
46 : ((ref) == USART2) ? cmuClock_USART2 \
47 : -1)
48 #elif (USART_COUNT == 4)
49 #define CLOCK_USART(ref) (((ref) == USART0) ? cmuClock_USART0 \
50 : ((ref) == USART1) ? cmuClock_USART1 \
51 : ((ref) == USART2) ? cmuClock_USART2 \
52 : ((ref) == USART3) ? cmuClock_USART3 \
53 : -1)
54 #elif (USART_COUNT == 5)
55 #define CLOCK_USART(ref) (((ref) == USART0) ? cmuClock_USART0 \
56 : ((ref) == USART1) ? cmuClock_USART1 \
57 : ((ref) == USART2) ? cmuClock_USART2 \
58 : ((ref) == USART3) ? cmuClock_USART3 \
59 : ((ref) == USART4) ? cmuClock_USART4 \
60 : -1)
61 #elif (USART_COUNT == 6)
62 #define CLOCK_USART(ref) (((ref) == USART0) ? cmuClock_USART0 \
63 : ((ref) == USART1) ? cmuClock_USART1 \
64 : ((ref) == USART2) ? cmuClock_USART2 \
65 : ((ref) == USART3) ? cmuClock_USART3 \
66 : ((ref) == USART4) ? cmuClock_USART4 \
67 : ((ref) == USART5) ? cmuClock_USART5 \
68 : -1)
69 #else
70 #error "Undefined number of USARTs."
71 #endif /* USART_COUNT */
72 #define GET_GECKO_USART_CLOCK(id) CLOCK_USART((USART_TypeDef *)DT_INST_REG_ADDR(id))
73 #endif /* DT_NODE_HAS_PROP(n, peripheral_id) */
74
75
76 #define SPI_WORD_SIZE 8
77
78 /* Structure Declarations */
79
80 struct spi_gecko_data {
81 struct spi_context ctx;
82 };
83
84 struct spi_gecko_config {
85 USART_TypeDef *base;
86 CMU_Clock_TypeDef clock;
87 uint32_t clock_frequency;
88 #ifdef CONFIG_PINCTRL
89 const struct pinctrl_dev_config *pcfg;
90 #else
91 struct soc_gpio_pin pin_rx;
92 struct soc_gpio_pin pin_tx;
93 struct soc_gpio_pin pin_clk;
94 uint8_t loc_rx;
95 uint8_t loc_tx;
96 uint8_t loc_clk;
97 #endif /* CONFIG_PINCTRL */
98 };
99
100
101 /* Helper Functions */
spi_config(const struct device * dev,const struct spi_config * config,uint16_t * control)102 static int spi_config(const struct device *dev,
103 const struct spi_config *config,
104 uint16_t *control)
105 {
106 const struct spi_gecko_config *gecko_config = dev->config;
107 struct spi_gecko_data *data = dev->data;
108 uint32_t spi_frequency = CMU_ClockFreqGet(gecko_config->clock) / 2;
109
110 if (config->operation & SPI_HALF_DUPLEX) {
111 LOG_ERR("Half-duplex not supported");
112 return -ENOTSUP;
113 }
114
115 if (SPI_WORD_SIZE_GET(config->operation) != SPI_WORD_SIZE) {
116 LOG_ERR("Word size must be %d", SPI_WORD_SIZE);
117 return -ENOTSUP;
118 }
119
120 if (config->operation & SPI_CS_ACTIVE_HIGH) {
121 LOG_ERR("CS active high not supported");
122 return -ENOTSUP;
123 }
124
125 if (config->operation & SPI_LOCK_ON) {
126 LOG_ERR("Lock On not supported");
127 return -ENOTSUP;
128 }
129
130 if (IS_ENABLED(CONFIG_SPI_EXTENDED_MODES) &&
131 (config->operation & SPI_LINES_MASK) != SPI_LINES_SINGLE) {
132 LOG_ERR("Only supports single mode");
133 return -ENOTSUP;
134 }
135
136 if (config->operation & SPI_TRANSFER_LSB) {
137 LOG_ERR("LSB first not supported");
138 return -ENOTSUP;
139 }
140
141 if (config->operation & SPI_OP_MODE_SLAVE) {
142 LOG_ERR("Slave mode not supported");
143 return -ENOTSUP;
144 }
145
146 /* Set frequency to the minimum of what the device supports, what the
147 * user has configured the controller to, and the max frequency for the
148 * transaction.
149 */
150 if (gecko_config->clock_frequency > spi_frequency) {
151 LOG_ERR("SPI clock-frequency too high");
152 return -EINVAL;
153 }
154 spi_frequency = MIN(gecko_config->clock_frequency, spi_frequency);
155 if (config->frequency) {
156 spi_frequency = MIN(config->frequency, spi_frequency);
157 }
158 USART_BaudrateSyncSet(gecko_config->base, 0, spi_frequency);
159
160 /* Set Loopback */
161 if (config->operation & SPI_MODE_LOOP) {
162 gecko_config->base->CTRL |= USART_CTRL_LOOPBK;
163 } else {
164 gecko_config->base->CTRL &= ~USART_CTRL_LOOPBK;
165 }
166
167 /* Set CPOL */
168 if (config->operation & SPI_MODE_CPOL) {
169 gecko_config->base->CTRL |= USART_CTRL_CLKPOL;
170 } else {
171 gecko_config->base->CTRL &= ~USART_CTRL_CLKPOL;
172 }
173
174 /* Set CPHA */
175 if (config->operation & SPI_MODE_CPHA) {
176 gecko_config->base->CTRL |= USART_CTRL_CLKPHA;
177 } else {
178 gecko_config->base->CTRL &= ~USART_CTRL_CLKPHA;
179 }
180
181 /* Set word size */
182 gecko_config->base->FRAME = usartDatabits8
183 | USART_FRAME_STOPBITS_DEFAULT
184 | USART_FRAME_PARITY_DEFAULT;
185
186 /* At this point, it's mandatory to set this on the context! */
187 data->ctx.config = config;
188
189 return 0;
190 }
191
spi_gecko_send(USART_TypeDef * usart,uint8_t frame)192 static void spi_gecko_send(USART_TypeDef *usart, uint8_t frame)
193 {
194 /* Write frame to register */
195 USART_Tx(usart, frame);
196
197 /* Wait until the transfer ends */
198 while (!(usart->STATUS & USART_STATUS_TXC)) {
199 }
200 }
201
spi_gecko_recv(USART_TypeDef * usart)202 static uint8_t spi_gecko_recv(USART_TypeDef *usart)
203 {
204 /* Return data inside rx register */
205 return (uint8_t)usart->RXDATA;
206 }
207
spi_gecko_transfer_ongoing(struct spi_gecko_data * data)208 static bool spi_gecko_transfer_ongoing(struct spi_gecko_data *data)
209 {
210 return spi_context_tx_on(&data->ctx) || spi_context_rx_on(&data->ctx);
211 }
212
spi_gecko_next_tx(struct spi_gecko_data * data)213 static inline uint8_t spi_gecko_next_tx(struct spi_gecko_data *data)
214 {
215 uint8_t tx_frame = 0;
216
217 if (spi_context_tx_buf_on(&data->ctx)) {
218 tx_frame = UNALIGNED_GET((uint8_t *)(data->ctx.tx_buf));
219 }
220
221 return tx_frame;
222 }
223
spi_gecko_shift_frames(USART_TypeDef * usart,struct spi_gecko_data * data)224 static int spi_gecko_shift_frames(USART_TypeDef *usart,
225 struct spi_gecko_data *data)
226 {
227 uint8_t tx_frame;
228 uint8_t rx_frame;
229
230 tx_frame = spi_gecko_next_tx(data);
231 spi_gecko_send(usart, tx_frame);
232 spi_context_update_tx(&data->ctx, 1, 1);
233
234 rx_frame = spi_gecko_recv(usart);
235
236 if (spi_context_rx_buf_on(&data->ctx)) {
237 UNALIGNED_PUT(rx_frame, (uint8_t *)data->ctx.rx_buf);
238 }
239 spi_context_update_rx(&data->ctx, 1, 1);
240 return 0;
241 }
242
243
spi_gecko_xfer(const struct device * dev,const struct spi_config * config)244 static void spi_gecko_xfer(const struct device *dev,
245 const struct spi_config *config)
246 {
247 int ret;
248 struct spi_gecko_data *data = dev->data;
249 struct spi_context *ctx = &data->ctx;
250 const struct spi_gecko_config *gecko_config = dev->config;
251
252 spi_context_cs_control(ctx, true);
253
254 do {
255 ret = spi_gecko_shift_frames(gecko_config->base, data);
256 } while (!ret && spi_gecko_transfer_ongoing(data));
257
258 spi_context_cs_control(ctx, false);
259 spi_context_complete(ctx, dev, 0);
260 }
261
262 #ifndef CONFIG_PINCTRL
spi_gecko_init_pins(const struct device * dev)263 static void spi_gecko_init_pins(const struct device *dev)
264 {
265 const struct spi_gecko_config *config = dev->config;
266
267 GPIO_PinModeSet(config->pin_rx.port, config->pin_rx.pin,
268 config->pin_rx.mode, config->pin_rx.out);
269 GPIO_PinModeSet(config->pin_tx.port, config->pin_tx.pin,
270 config->pin_tx.mode, config->pin_tx.out);
271 GPIO_PinModeSet(config->pin_clk.port, config->pin_clk.pin,
272 config->pin_clk.mode, config->pin_clk.out);
273
274 /* disable all pins while configuring */
275 config->base->ROUTEPEN = 0;
276
277 config->base->ROUTELOC0 =
278 (config->loc_tx << _USART_ROUTELOC0_TXLOC_SHIFT) |
279 (config->loc_rx << _USART_ROUTELOC0_RXLOC_SHIFT) |
280 (config->loc_clk << _USART_ROUTELOC0_CLKLOC_SHIFT);
281
282 config->base->ROUTELOC1 = _USART_ROUTELOC1_RESETVALUE;
283
284 config->base->ROUTEPEN = USART_ROUTEPEN_RXPEN | USART_ROUTEPEN_TXPEN |
285 USART_ROUTEPEN_CLKPEN;
286 }
287 #endif /* !CONFIG_PINCTRL */
288
289
290 /* API Functions */
291
spi_gecko_init(const struct device * dev)292 static int spi_gecko_init(const struct device *dev)
293 {
294 int err;
295 const struct spi_gecko_config *config = dev->config;
296 struct spi_gecko_data *data = dev->data;
297 USART_InitSync_TypeDef usartInit = USART_INITSYNC_DEFAULT;
298
299 /* The peripheral and gpio clock are already enabled from soc and gpio
300 * driver
301 */
302
303 usartInit.enable = usartDisable;
304 usartInit.baudrate = 1000000;
305 usartInit.databits = usartDatabits8;
306 usartInit.master = 1;
307 usartInit.msbf = 1;
308 usartInit.clockMode = usartClockMode0;
309 #if defined(USART_INPUT_RXPRS) && defined(USART_TRIGCTRL_AUTOTXTEN)
310 usartInit.prsRxEnable = 0;
311 usartInit.prsRxCh = 0;
312 usartInit.autoTx = 0;
313 #endif
314
315 /* Enable USART clock */
316 CMU_ClockEnable(config->clock, true);
317
318 /* Init USART */
319 USART_InitSync(config->base, &usartInit);
320
321 #ifdef CONFIG_PINCTRL
322 err = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
323 if (err < 0) {
324 return err;
325 }
326 #else
327 /* Initialize USART pins */
328 spi_gecko_init_pins(dev);
329 #endif /* CONFIG_PINCTRL */
330
331 err = spi_context_cs_configure_all(&data->ctx);
332 if (err < 0) {
333 return err;
334 }
335
336 /* Enable the peripheral */
337 config->base->CMD = (uint32_t) usartEnable;
338
339 return 0;
340 }
341
spi_gecko_transceive(const struct device * dev,const struct spi_config * config,const struct spi_buf_set * tx_bufs,const struct spi_buf_set * rx_bufs)342 static int spi_gecko_transceive(const struct device *dev,
343 const struct spi_config *config,
344 const struct spi_buf_set *tx_bufs,
345 const struct spi_buf_set *rx_bufs)
346 {
347 struct spi_gecko_data *data = dev->data;
348 uint16_t control = 0;
349 int ret;
350
351 ret = spi_config(dev, config, &control);
352 if (ret < 0) {
353 return ret;
354 }
355
356 spi_context_buffers_setup(&data->ctx, tx_bufs, rx_bufs, 1);
357 spi_gecko_xfer(dev, config);
358 return 0;
359 }
360
361 #ifdef CONFIG_SPI_ASYNC
spi_gecko_transceive_async(const struct device * dev,const struct spi_config * config,const struct spi_buf_set * tx_bufs,const struct spi_buf_set * rx_bufs,struct k_poll_signal * async)362 static int spi_gecko_transceive_async(const struct device *dev,
363 const struct spi_config *config,
364 const struct spi_buf_set *tx_bufs,
365 const struct spi_buf_set *rx_bufs,
366 struct k_poll_signal *async)
367 {
368 return -ENOTSUP;
369 }
370 #endif /* CONFIG_SPI_ASYNC */
371
spi_gecko_release(const struct device * dev,const struct spi_config * config)372 static int spi_gecko_release(const struct device *dev,
373 const struct spi_config *config)
374 {
375 const struct spi_gecko_config *gecko_config = dev->config;
376
377 if (!(gecko_config->base->STATUS & USART_STATUS_TXIDLE)) {
378 return -EBUSY;
379 }
380 return 0;
381 }
382
383 /* Device Instantiation */
384 static const struct spi_driver_api spi_gecko_api = {
385 .transceive = spi_gecko_transceive,
386 #ifdef CONFIG_SPI_ASYNC
387 .transceive_async = spi_gecko_transceive_async,
388 #endif /* CONFIG_SPI_ASYNC */
389 .release = spi_gecko_release,
390 };
391
392 #ifdef CONFIG_PINCTRL
393 #define SPI_INIT(n) \
394 PINCTRL_DT_INST_DEFINE(n); \
395 static struct spi_gecko_data spi_gecko_data_##n = { \
396 SPI_CONTEXT_INIT_LOCK(spi_gecko_data_##n, ctx), \
397 SPI_CONTEXT_INIT_SYNC(spi_gecko_data_##n, ctx), \
398 SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(n), ctx) \
399 }; \
400 static struct spi_gecko_config spi_gecko_cfg_##n = { \
401 .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \
402 .base = (USART_TypeDef *) \
403 DT_INST_REG_ADDR(n), \
404 .clock = GET_GECKO_USART_CLOCK(n), \
405 .clock_frequency = DT_INST_PROP_OR(n, clock_frequency, 1000000) \
406 }; \
407 DEVICE_DT_INST_DEFINE(n, \
408 spi_gecko_init, \
409 NULL, \
410 &spi_gecko_data_##n, \
411 &spi_gecko_cfg_##n, \
412 POST_KERNEL, \
413 CONFIG_SPI_INIT_PRIORITY, \
414 &spi_gecko_api);
415 #else
416 #define SPI_INIT(n) \
417 static struct spi_gecko_data spi_gecko_data_##n = { \
418 SPI_CONTEXT_INIT_LOCK(spi_gecko_data_##n, ctx), \
419 SPI_CONTEXT_INIT_SYNC(spi_gecko_data_##n, ctx), \
420 SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(n), ctx) \
421 }; \
422 static struct spi_gecko_config spi_gecko_cfg_##n = { \
423 .base = (USART_TypeDef *) \
424 DT_INST_REG_ADDR(n), \
425 .clock = GET_GECKO_USART_CLOCK(n), \
426 .clock_frequency = DT_INST_PROP_OR(n, clock_frequency, 1000000), \
427 .pin_rx = { DT_INST_PROP_BY_IDX(n, location_rx, 1), \
428 DT_INST_PROP_BY_IDX(n, location_rx, 2), \
429 gpioModeInput, 1}, \
430 .pin_tx = { DT_INST_PROP_BY_IDX(n, location_tx, 1), \
431 DT_INST_PROP_BY_IDX(n, location_tx, 2), \
432 gpioModePushPull, 1}, \
433 .pin_clk = { DT_INST_PROP_BY_IDX(n, location_clk, 1), \
434 DT_INST_PROP_BY_IDX(n, location_clk, 2), \
435 gpioModePushPull, 1}, \
436 .loc_rx = DT_INST_PROP_BY_IDX(n, location_rx, 0), \
437 .loc_tx = DT_INST_PROP_BY_IDX(n, location_tx, 0), \
438 .loc_clk = DT_INST_PROP_BY_IDX(n, location_clk, 0), \
439 }; \
440 DEVICE_DT_INST_DEFINE(n, \
441 spi_gecko_init, \
442 NULL, \
443 &spi_gecko_data_##n, \
444 &spi_gecko_cfg_##n, \
445 POST_KERNEL, \
446 CONFIG_SPI_INIT_PRIORITY, \
447 &spi_gecko_api);
448 #endif /* CONFIG_PINCTRL */
449
450 DT_INST_FOREACH_STATUS_OKAY(SPI_INIT)
451