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