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