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