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