1 /*
2  * Copyright (c) 2019 Brett Witherspoon
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT ti_cc13xx_cc26xx_spi
8 
9 #define LOG_LEVEL CONFIG_SPI_LOG_LEVEL
10 #include <zephyr/logging/log.h>
11 LOG_MODULE_REGISTER(spi_cc13xx_cc26xx);
12 
13 #include <zephyr/drivers/spi.h>
14 #include <zephyr/drivers/spi/rtio.h>
15 #include <zephyr/drivers/pinctrl.h>
16 #include <zephyr/pm/device.h>
17 #include <zephyr/pm/policy.h>
18 
19 #include <driverlib/prcm.h>
20 #include <driverlib/ssi.h>
21 
22 #include <ti/drivers/Power.h>
23 #include <ti/drivers/power/PowerCC26X2.h>
24 
25 #include "spi_context.h"
26 
27 struct spi_cc13xx_cc26xx_config {
28 	uint32_t base;
29 	const struct pinctrl_dev_config *pcfg;
30 };
31 
32 struct spi_cc13xx_cc26xx_data {
33 	struct spi_context ctx;
34 };
35 
36 #define CPU_FREQ DT_PROP(DT_PATH(cpus, cpu_0), clock_frequency)
37 
spi_cc13xx_cc26xx_configure(const struct device * dev,const struct spi_config * config)38 static int spi_cc13xx_cc26xx_configure(const struct device *dev,
39 				       const struct spi_config *config)
40 {
41 	const struct spi_cc13xx_cc26xx_config *cfg = dev->config;
42 	struct spi_cc13xx_cc26xx_data *data = dev->data;
43 	struct spi_context *ctx = &data->ctx;
44 	uint32_t prot;
45 	int ret;
46 
47 	if (spi_context_configured(ctx, config)) {
48 		return 0;
49 	}
50 
51 	if (config->operation & SPI_HALF_DUPLEX) {
52 		LOG_ERR("Half-duplex not supported");
53 		return -ENOTSUP;
54 	}
55 
56 	/* Slave mode has not been implemented */
57 	if (SPI_OP_MODE_GET(config->operation) != SPI_OP_MODE_MASTER) {
58 		LOG_ERR("Slave mode is not supported");
59 		return -ENOTSUP;
60 	}
61 
62 	/* Word sizes other than 8 bits has not been implemented */
63 	if (SPI_WORD_SIZE_GET(config->operation) != 8) {
64 		LOG_ERR("Word sizes other than 8 bits are not supported");
65 		return -ENOTSUP;
66 	}
67 
68 	if (config->operation & SPI_TRANSFER_LSB) {
69 		LOG_ERR("Transfer LSB first mode is not supported");
70 		return -EINVAL;
71 	}
72 
73 	if (IS_ENABLED(CONFIG_SPI_EXTENDED_MODES) &&
74 	    (config->operation & SPI_LINES_MASK) != SPI_LINES_SINGLE) {
75 		LOG_ERR("Multiple lines are not supported");
76 		return -EINVAL;
77 	}
78 
79 	if (config->operation & SPI_CS_ACTIVE_HIGH && !spi_cs_is_gpio(config)) {
80 		LOG_ERR("Active high CS requires emulation through a GPIO line.");
81 		return -EINVAL;
82 	}
83 
84 	if (config->frequency < 2000000) {
85 		LOG_ERR("Frequencies lower than 2 MHz are not supported");
86 		return -EINVAL;
87 	}
88 
89 	if (2 * config->frequency > CPU_FREQ) {
90 		LOG_ERR("Frequency greater than supported in master mode");
91 		return -EINVAL;
92 	}
93 
94 	if (SPI_MODE_GET(config->operation) & SPI_MODE_CPOL) {
95 		if (SPI_MODE_GET(config->operation) & SPI_MODE_CPHA) {
96 			prot = SSI_FRF_MOTO_MODE_3;
97 		} else {
98 			prot = SSI_FRF_MOTO_MODE_2;
99 		}
100 	} else {
101 		if (SPI_MODE_GET(config->operation) & SPI_MODE_CPHA) {
102 			prot = SSI_FRF_MOTO_MODE_1;
103 		} else {
104 			prot = SSI_FRF_MOTO_MODE_0;
105 		}
106 	}
107 
108 	ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT);
109 	if (ret < 0) {
110 		LOG_ERR("applying SPI pinctrl state failed");
111 		return ret;
112 	}
113 
114 	ctx->config = config;
115 
116 	/* Disable SSI before making configuration changes */
117 	SSIDisable(cfg->base);
118 
119 	/* Configure SSI */
120 	SSIConfigSetExpClk(cfg->base, CPU_FREQ, prot,
121 			   SSI_MODE_MASTER, config->frequency, 8);
122 
123 	if (SPI_MODE_GET(config->operation) & SPI_MODE_LOOP) {
124 		sys_set_bit(cfg->base + SSI_O_CR1, 0);
125 	}
126 
127 	/* Re-enable SSI after making configuration changes */
128 	SSIEnable(cfg->base);
129 
130 	return 0;
131 }
132 
spi_cc13xx_cc26xx_transceive(const struct device * dev,const struct spi_config * config,const struct spi_buf_set * tx_bufs,const struct spi_buf_set * rx_bufs)133 static int spi_cc13xx_cc26xx_transceive(const struct device *dev,
134 					const struct spi_config *config,
135 					const struct spi_buf_set *tx_bufs,
136 					const struct spi_buf_set *rx_bufs)
137 {
138 	const struct spi_cc13xx_cc26xx_config *cfg = dev->config;
139 	struct spi_cc13xx_cc26xx_data *data = dev->data;
140 	struct spi_context *ctx = &data->ctx;
141 	uint32_t txd, rxd;
142 	int err;
143 
144 	spi_context_lock(ctx, false, NULL, NULL, config);
145 	pm_policy_state_lock_get(PM_STATE_STANDBY, PM_ALL_SUBSTATES);
146 
147 	err = spi_cc13xx_cc26xx_configure(dev, config);
148 	if (err) {
149 		goto done;
150 	}
151 
152 	spi_context_buffers_setup(ctx, tx_bufs, rx_bufs, 1);
153 
154 	spi_context_cs_control(ctx, true);
155 
156 	do {
157 		if (spi_context_tx_buf_on(ctx)) {
158 			txd = *ctx->tx_buf;
159 		} else {
160 			txd = 0U;
161 		}
162 
163 		SSIDataPut(cfg->base, txd);
164 
165 		spi_context_update_tx(ctx, 1, 1);
166 
167 		SSIDataGet(cfg->base, &rxd);
168 
169 		if (spi_context_rx_buf_on(ctx)) {
170 			*ctx->rx_buf = rxd;
171 		}
172 
173 		spi_context_update_rx(ctx, 1, 1);
174 	} while (spi_context_tx_on(ctx) || spi_context_rx_on(ctx));
175 
176 	spi_context_cs_control(ctx, false);
177 
178 done:
179 	pm_policy_state_lock_put(PM_STATE_STANDBY, PM_ALL_SUBSTATES);
180 	spi_context_release(ctx, err);
181 	return err;
182 }
183 
spi_cc13xx_cc26xx_release(const struct device * dev,const struct spi_config * config)184 static int spi_cc13xx_cc26xx_release(const struct device *dev,
185 				     const struct spi_config *config)
186 {
187 	const struct spi_cc13xx_cc26xx_config *cfg = dev->config;
188 	struct spi_cc13xx_cc26xx_data *data = dev->data;
189 	struct spi_context *ctx = &data->ctx;
190 
191 	if (!spi_context_configured(ctx, config)) {
192 		return -EINVAL;
193 	}
194 
195 	if (SSIBusy(cfg->base)) {
196 		return -EBUSY;
197 	}
198 
199 	spi_context_unlock_unconditionally(ctx);
200 
201 	return 0;
202 }
203 
204 #ifdef CONFIG_PM_DEVICE
spi_cc13xx_cc26xx_pm_action(const struct device * dev,enum pm_device_action action)205 static int spi_cc13xx_cc26xx_pm_action(const struct device *dev,
206 				       enum pm_device_action action)
207 {
208 	const struct spi_cc13xx_cc26xx_config *config = dev->config;
209 
210 	switch (action) {
211 	case PM_DEVICE_ACTION_RESUME:
212 		if (config->base == DT_INST_REG_ADDR(0)) {
213 			Power_setDependency(PowerCC26XX_PERIPH_SSI0);
214 		} else {
215 			Power_setDependency(PowerCC26XX_PERIPH_SSI1);
216 		}
217 		break;
218 	case PM_DEVICE_ACTION_SUSPEND:
219 		SSIDisable(config->base);
220 		/*
221 		 * Release power dependency
222 		 */
223 		if (config->base == DT_INST_REG_ADDR(0)) {
224 			Power_releaseDependency(PowerCC26XX_PERIPH_SSI0);
225 		} else {
226 			Power_releaseDependency(PowerCC26XX_PERIPH_SSI1);
227 		}
228 		break;
229 	default:
230 		return -ENOTSUP;
231 	}
232 
233 	return 0;
234 }
235 #endif /* CONFIG_PM_DEVICE */
236 
237 
238 static DEVICE_API(spi, spi_cc13xx_cc26xx_driver_api) = {
239 	.transceive = spi_cc13xx_cc26xx_transceive,
240 	.release = spi_cc13xx_cc26xx_release,
241 #ifdef CONFIG_SPI_RTIO
242 	.iodev_submit = spi_rtio_iodev_default_submit,
243 #endif
244 };
245 
246 #ifdef CONFIG_PM
247 #define SPI_CC13XX_CC26XX_POWER_SPI(n)					  \
248 	do {								  \
249 		/* Set Power dependencies & constraints */		  \
250 		if (DT_INST_REG_ADDR(n) == 0x40000000) {		  \
251 			Power_setDependency(PowerCC26XX_PERIPH_SSI0);	  \
252 		} else {						  \
253 			Power_setDependency(PowerCC26XX_PERIPH_SSI1);	  \
254 		}							  \
255 	} while (false)
256 #else
257 #define SPI_CC13XX_CC26XX_POWER_SPI(n)					  \
258 	do {								  \
259 		uint32_t domain, periph;				  \
260 									  \
261 		/* Enable UART power domain */				  \
262 		if (DT_INST_REG_ADDR(n) == 0x40000000) {		  \
263 			domain = PRCM_DOMAIN_SERIAL;			  \
264 			periph = PRCM_PERIPH_SSI0;			  \
265 		} else {						  \
266 			domain = PRCM_DOMAIN_PERIPH;			  \
267 			periph = PRCM_PERIPH_SSI1;			  \
268 		}							  \
269 		/* Enable SSI##n power domain */			  \
270 		PRCMPowerDomainOn(domain);				  \
271 									  \
272 		/* Enable SSI##n peripherals */				  \
273 		PRCMPeripheralRunEnable(periph);			  \
274 		PRCMPeripheralSleepEnable(periph);			  \
275 		PRCMPeripheralDeepSleepEnable(periph);			  \
276 									  \
277 		/* Load PRCM settings */				  \
278 		PRCMLoadSet();						  \
279 		while (!PRCMLoadGet()) {				  \
280 			continue;					  \
281 		}							  \
282 									  \
283 		/* SSI should not be accessed until power domain is on. */\
284 		while (PRCMPowerDomainsAllOn(domain) !=			  \
285 			PRCM_DOMAIN_POWER_ON) {				  \
286 			continue;					  \
287 		}							  \
288 	} while (false)
289 #endif
290 
291 #define SPI_CC13XX_CC26XX_DEVICE_INIT(n)				    \
292 	PM_DEVICE_DT_INST_DEFINE(n, spi_cc13xx_cc26xx_pm_action);	    \
293 									    \
294 	SPI_DEVICE_DT_INST_DEFINE(n,					    \
295 		spi_cc13xx_cc26xx_init_##n,				    \
296 		PM_DEVICE_DT_INST_GET(n),				    \
297 		&spi_cc13xx_cc26xx_data_##n, &spi_cc13xx_cc26xx_config_##n, \
298 		POST_KERNEL, CONFIG_SPI_INIT_PRIORITY,			    \
299 		&spi_cc13xx_cc26xx_driver_api)
300 
301 #define SPI_CC13XX_CC26XX_INIT_FUNC(n)						\
302 	static int spi_cc13xx_cc26xx_init_##n(const struct device *dev)		\
303 	{									\
304 		struct spi_cc13xx_cc26xx_data *data = dev->data;		\
305 		int err;							\
306 		SPI_CC13XX_CC26XX_POWER_SPI(n);					\
307 										\
308 		err = spi_context_cs_configure_all(&data->ctx);			\
309 		if (err < 0) {							\
310 			return err;						\
311 		}								\
312 										\
313 		spi_context_unlock_unconditionally(&data->ctx);			\
314 										\
315 		return 0;							\
316 	}
317 
318 #define SPI_CC13XX_CC26XX_INIT(n)					\
319 	PINCTRL_DT_INST_DEFINE(n);	\
320 	SPI_CC13XX_CC26XX_INIT_FUNC(n)					\
321 									\
322 	static const struct spi_cc13xx_cc26xx_config			\
323 		spi_cc13xx_cc26xx_config_##n = {			\
324 		.base = DT_INST_REG_ADDR(n),				\
325 		.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n) \
326 	};								\
327 									\
328 	static struct spi_cc13xx_cc26xx_data				\
329 		spi_cc13xx_cc26xx_data_##n = {				\
330 		SPI_CONTEXT_INIT_LOCK(spi_cc13xx_cc26xx_data_##n, ctx),	\
331 		SPI_CONTEXT_INIT_SYNC(spi_cc13xx_cc26xx_data_##n, ctx),	\
332 		SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(n), ctx)	\
333 	};								\
334 									\
335 	SPI_CC13XX_CC26XX_DEVICE_INIT(n);
336 
337 DT_INST_FOREACH_STATUS_OKAY(SPI_CC13XX_CC26XX_INIT)
338