xref: /aosp_15_r20/external/arm-trusted-firmware/drivers/mtd/spi-mem/spi_mem.c (revision 54fd6939e177f8ff529b10183254802c76df6d08)
1 /*
2  * Copyright (c) 2019, STMicroelectronics - All Rights Reserved
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <assert.h>
8 #include <inttypes.h>
9 #include <stdint.h>
10 
11 #include <libfdt.h>
12 
13 #include <drivers/spi_mem.h>
14 #include <lib/utils_def.h>
15 
16 #define SPI_MEM_DEFAULT_SPEED_HZ 100000U
17 
18 /*
19  * struct spi_slave - Representation of a SPI slave.
20  *
21  * @max_hz:		Maximum speed for this slave in Hertz.
22  * @cs:			ID of the chip select connected to the slave.
23  * @mode:		SPI mode to use for this slave (see SPI mode flags).
24  * @ops:		Ops defined by the bus.
25  */
26 struct spi_slave {
27 	unsigned int max_hz;
28 	unsigned int cs;
29 	unsigned int mode;
30 	const struct spi_bus_ops *ops;
31 };
32 
33 static struct spi_slave spi_slave;
34 
spi_mem_check_buswidth_req(uint8_t buswidth,bool tx)35 static bool spi_mem_check_buswidth_req(uint8_t buswidth, bool tx)
36 {
37 	switch (buswidth) {
38 	case 1U:
39 		return true;
40 
41 	case 2U:
42 		if ((tx && (spi_slave.mode & (SPI_TX_DUAL | SPI_TX_QUAD)) !=
43 		     0U) ||
44 		    (!tx && (spi_slave.mode & (SPI_RX_DUAL | SPI_RX_QUAD)) !=
45 		     0U)) {
46 			return true;
47 		}
48 		break;
49 
50 	case 4U:
51 		if ((tx && (spi_slave.mode & SPI_TX_QUAD) != 0U) ||
52 		    (!tx && (spi_slave.mode & SPI_RX_QUAD) != 0U)) {
53 			return true;
54 		}
55 		break;
56 
57 	default:
58 		break;
59 	}
60 
61 	return false;
62 }
63 
spi_mem_supports_op(const struct spi_mem_op * op)64 static bool spi_mem_supports_op(const struct spi_mem_op *op)
65 {
66 	if (!spi_mem_check_buswidth_req(op->cmd.buswidth, true)) {
67 		return false;
68 	}
69 
70 	if ((op->addr.nbytes != 0U) &&
71 	    !spi_mem_check_buswidth_req(op->addr.buswidth, true)) {
72 		return false;
73 	}
74 
75 	if ((op->dummy.nbytes != 0U) &&
76 	    !spi_mem_check_buswidth_req(op->dummy.buswidth, true)) {
77 		return false;
78 	}
79 
80 	if ((op->data.nbytes != 0U) &&
81 	    !spi_mem_check_buswidth_req(op->data.buswidth,
82 				       op->data.dir == SPI_MEM_DATA_OUT)) {
83 		return false;
84 	}
85 
86 	return true;
87 }
88 
spi_mem_set_speed_mode(void)89 static int spi_mem_set_speed_mode(void)
90 {
91 	const struct spi_bus_ops *ops = spi_slave.ops;
92 	int ret;
93 
94 	ret = ops->set_speed(spi_slave.max_hz);
95 	if (ret != 0) {
96 		VERBOSE("Cannot set speed (err=%d)\n", ret);
97 		return ret;
98 	}
99 
100 	ret = ops->set_mode(spi_slave.mode);
101 	if (ret != 0) {
102 		VERBOSE("Cannot set mode (err=%d)\n", ret);
103 		return ret;
104 	}
105 
106 	return 0;
107 }
108 
spi_mem_check_bus_ops(const struct spi_bus_ops * ops)109 static int spi_mem_check_bus_ops(const struct spi_bus_ops *ops)
110 {
111 	bool error = false;
112 
113 	if (ops->claim_bus == NULL) {
114 		VERBOSE("Ops claim bus is not defined\n");
115 		error = true;
116 	}
117 
118 	if (ops->release_bus == NULL) {
119 		VERBOSE("Ops release bus is not defined\n");
120 		error = true;
121 	}
122 
123 	if (ops->exec_op == NULL) {
124 		VERBOSE("Ops exec op is not defined\n");
125 		error = true;
126 	}
127 
128 	if (ops->set_speed == NULL) {
129 		VERBOSE("Ops set speed is not defined\n");
130 		error = true;
131 	}
132 
133 	if (ops->set_mode == NULL) {
134 		VERBOSE("Ops set mode is not defined\n");
135 		error = true;
136 	}
137 
138 	return error ? -EINVAL : 0;
139 }
140 
141 /*
142  * spi_mem_exec_op() - Execute a memory operation.
143  * @op: The memory operation to execute.
144  *
145  * This function first checks that @op is supported and then tries to execute
146  * it.
147  *
148  * Return: 0 in case of success, a negative error code otherwise.
149  */
spi_mem_exec_op(const struct spi_mem_op * op)150 int spi_mem_exec_op(const struct spi_mem_op *op)
151 {
152 	const struct spi_bus_ops *ops = spi_slave.ops;
153 	int ret;
154 
155 	VERBOSE("%s: cmd:%x mode:%d.%d.%d.%d addqr:%" PRIx64 " len:%x\n",
156 		__func__, op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth,
157 		op->dummy.buswidth, op->data.buswidth,
158 		op->addr.val, op->data.nbytes);
159 
160 	if (!spi_mem_supports_op(op)) {
161 		WARN("Error in spi_mem_support\n");
162 		return -ENOTSUP;
163 	}
164 
165 	ret = ops->claim_bus(spi_slave.cs);
166 	if (ret != 0) {
167 		WARN("Error claim_bus\n");
168 		return ret;
169 	}
170 
171 	ret = ops->exec_op(op);
172 
173 	ops->release_bus();
174 
175 	return ret;
176 }
177 
178 /*
179  * spi_mem_init_slave() - SPI slave device initialization.
180  * @fdt: Pointer to the device tree blob.
181  * @bus_node: Offset of the bus node.
182  * @ops: The SPI bus ops defined.
183  *
184  * This function first checks that @ops are supported and then tries to find
185  * a SPI slave device.
186  *
187  * Return: 0 in case of success, a negative error code otherwise.
188  */
spi_mem_init_slave(void * fdt,int bus_node,const struct spi_bus_ops * ops)189 int spi_mem_init_slave(void *fdt, int bus_node, const struct spi_bus_ops *ops)
190 {
191 	int ret;
192 	int mode = 0;
193 	int nchips = 0;
194 	int bus_subnode = 0;
195 	const fdt32_t *cuint = NULL;
196 
197 	ret = spi_mem_check_bus_ops(ops);
198 	if (ret != 0) {
199 		return ret;
200 	}
201 
202 	fdt_for_each_subnode(bus_subnode, fdt, bus_node) {
203 		nchips++;
204 	}
205 
206 	if (nchips != 1) {
207 		ERROR("Only one SPI device is currently supported\n");
208 		return -EINVAL;
209 	}
210 
211 	fdt_for_each_subnode(bus_subnode, fdt, bus_node) {
212 		/* Get chip select */
213 		cuint = fdt_getprop(fdt, bus_subnode, "reg", NULL);
214 		if (cuint == NULL) {
215 			ERROR("Chip select not well defined\n");
216 			return -EINVAL;
217 		}
218 		spi_slave.cs = fdt32_to_cpu(*cuint);
219 
220 		/* Get max slave frequency */
221 		spi_slave.max_hz = SPI_MEM_DEFAULT_SPEED_HZ;
222 		cuint = fdt_getprop(fdt, bus_subnode,
223 				    "spi-max-frequency", NULL);
224 		if (cuint != NULL) {
225 			spi_slave.max_hz = fdt32_to_cpu(*cuint);
226 		}
227 
228 		/* Get mode */
229 		if ((fdt_getprop(fdt, bus_subnode, "spi-cpol", NULL)) != NULL) {
230 			mode |= SPI_CPOL;
231 		}
232 		if ((fdt_getprop(fdt, bus_subnode, "spi-cpha", NULL)) != NULL) {
233 			mode |= SPI_CPHA;
234 		}
235 		if ((fdt_getprop(fdt, bus_subnode, "spi-cs-high", NULL)) !=
236 		    NULL) {
237 			mode |= SPI_CS_HIGH;
238 		}
239 		if ((fdt_getprop(fdt, bus_subnode, "spi-3wire", NULL)) !=
240 		    NULL) {
241 			mode |= SPI_3WIRE;
242 		}
243 		if ((fdt_getprop(fdt, bus_subnode, "spi-half-duplex", NULL)) !=
244 		    NULL) {
245 			mode |= SPI_PREAMBLE;
246 		}
247 
248 		/* Get dual/quad mode */
249 		cuint = fdt_getprop(fdt, bus_subnode, "spi-tx-bus-width", NULL);
250 		if (cuint != NULL) {
251 			switch (fdt32_to_cpu(*cuint)) {
252 			case 1U:
253 				break;
254 			case 2U:
255 				mode |= SPI_TX_DUAL;
256 				break;
257 			case 4U:
258 				mode |= SPI_TX_QUAD;
259 				break;
260 			default:
261 				WARN("spi-tx-bus-width %d not supported\n",
262 				     fdt32_to_cpu(*cuint));
263 				return -EINVAL;
264 			}
265 		}
266 
267 		cuint = fdt_getprop(fdt, bus_subnode, "spi-rx-bus-width", NULL);
268 		if (cuint != NULL) {
269 			switch (fdt32_to_cpu(*cuint)) {
270 			case 1U:
271 				break;
272 			case 2U:
273 				mode |= SPI_RX_DUAL;
274 				break;
275 			case 4U:
276 				mode |= SPI_RX_QUAD;
277 				break;
278 			default:
279 				WARN("spi-rx-bus-width %d not supported\n",
280 				     fdt32_to_cpu(*cuint));
281 				return -EINVAL;
282 			}
283 		}
284 
285 		spi_slave.mode = mode;
286 		spi_slave.ops = ops;
287 	}
288 
289 	return spi_mem_set_speed_mode();
290 }
291