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