1967efcaeSBoris Brezillon // SPDX-License-Identifier: GPL-2.0+
2967efcaeSBoris Brezillon /*
3967efcaeSBoris Brezillon * Copyright (C) 2018 Exceet Electronics GmbH
4967efcaeSBoris Brezillon * Copyright (C) 2018 Bootlin
5967efcaeSBoris Brezillon *
6967efcaeSBoris Brezillon * Author: Boris Brezillon <boris.brezillon@bootlin.com>
7967efcaeSBoris Brezillon */
8967efcaeSBoris Brezillon
9967efcaeSBoris Brezillon #ifndef __UBOOT__
10967efcaeSBoris Brezillon #include <linux/dmaengine.h>
11967efcaeSBoris Brezillon #include <linux/pm_runtime.h>
12967efcaeSBoris Brezillon #include "internals.h"
13967efcaeSBoris Brezillon #else
14967efcaeSBoris Brezillon #include <spi.h>
15967efcaeSBoris Brezillon #include <spi-mem.h>
16967efcaeSBoris Brezillon #endif
17967efcaeSBoris Brezillon
18967efcaeSBoris Brezillon #ifndef __UBOOT__
19967efcaeSBoris Brezillon /**
20967efcaeSBoris Brezillon * spi_controller_dma_map_mem_op_data() - DMA-map the buffer attached to a
21967efcaeSBoris Brezillon * memory operation
22967efcaeSBoris Brezillon * @ctlr: the SPI controller requesting this dma_map()
23967efcaeSBoris Brezillon * @op: the memory operation containing the buffer to map
24967efcaeSBoris Brezillon * @sgt: a pointer to a non-initialized sg_table that will be filled by this
25967efcaeSBoris Brezillon * function
26967efcaeSBoris Brezillon *
27967efcaeSBoris Brezillon * Some controllers might want to do DMA on the data buffer embedded in @op.
28967efcaeSBoris Brezillon * This helper prepares everything for you and provides a ready-to-use
29967efcaeSBoris Brezillon * sg_table. This function is not intended to be called from spi drivers.
30967efcaeSBoris Brezillon * Only SPI controller drivers should use it.
31967efcaeSBoris Brezillon * Note that the caller must ensure the memory region pointed by
32967efcaeSBoris Brezillon * op->data.buf.{in,out} is DMA-able before calling this function.
33967efcaeSBoris Brezillon *
34967efcaeSBoris Brezillon * Return: 0 in case of success, a negative error code otherwise.
35967efcaeSBoris Brezillon */
spi_controller_dma_map_mem_op_data(struct spi_controller * ctlr,const struct spi_mem_op * op,struct sg_table * sgt)36967efcaeSBoris Brezillon int spi_controller_dma_map_mem_op_data(struct spi_controller *ctlr,
37967efcaeSBoris Brezillon const struct spi_mem_op *op,
38967efcaeSBoris Brezillon struct sg_table *sgt)
39967efcaeSBoris Brezillon {
40967efcaeSBoris Brezillon struct device *dmadev;
41967efcaeSBoris Brezillon
42967efcaeSBoris Brezillon if (!op->data.nbytes)
43967efcaeSBoris Brezillon return -EINVAL;
44967efcaeSBoris Brezillon
45967efcaeSBoris Brezillon if (op->data.dir == SPI_MEM_DATA_OUT && ctlr->dma_tx)
46967efcaeSBoris Brezillon dmadev = ctlr->dma_tx->device->dev;
47967efcaeSBoris Brezillon else if (op->data.dir == SPI_MEM_DATA_IN && ctlr->dma_rx)
48967efcaeSBoris Brezillon dmadev = ctlr->dma_rx->device->dev;
49967efcaeSBoris Brezillon else
50967efcaeSBoris Brezillon dmadev = ctlr->dev.parent;
51967efcaeSBoris Brezillon
52967efcaeSBoris Brezillon if (!dmadev)
53967efcaeSBoris Brezillon return -EINVAL;
54967efcaeSBoris Brezillon
55967efcaeSBoris Brezillon return spi_map_buf(ctlr, dmadev, sgt, op->data.buf.in, op->data.nbytes,
56967efcaeSBoris Brezillon op->data.dir == SPI_MEM_DATA_IN ?
57967efcaeSBoris Brezillon DMA_FROM_DEVICE : DMA_TO_DEVICE);
58967efcaeSBoris Brezillon }
59967efcaeSBoris Brezillon EXPORT_SYMBOL_GPL(spi_controller_dma_map_mem_op_data);
60967efcaeSBoris Brezillon
61967efcaeSBoris Brezillon /**
62967efcaeSBoris Brezillon * spi_controller_dma_unmap_mem_op_data() - DMA-unmap the buffer attached to a
63967efcaeSBoris Brezillon * memory operation
64967efcaeSBoris Brezillon * @ctlr: the SPI controller requesting this dma_unmap()
65967efcaeSBoris Brezillon * @op: the memory operation containing the buffer to unmap
66967efcaeSBoris Brezillon * @sgt: a pointer to an sg_table previously initialized by
67967efcaeSBoris Brezillon * spi_controller_dma_map_mem_op_data()
68967efcaeSBoris Brezillon *
69967efcaeSBoris Brezillon * Some controllers might want to do DMA on the data buffer embedded in @op.
70967efcaeSBoris Brezillon * This helper prepares things so that the CPU can access the
71967efcaeSBoris Brezillon * op->data.buf.{in,out} buffer again.
72967efcaeSBoris Brezillon *
73967efcaeSBoris Brezillon * This function is not intended to be called from SPI drivers. Only SPI
74967efcaeSBoris Brezillon * controller drivers should use it.
75967efcaeSBoris Brezillon *
76967efcaeSBoris Brezillon * This function should be called after the DMA operation has finished and is
77967efcaeSBoris Brezillon * only valid if the previous spi_controller_dma_map_mem_op_data() call
78967efcaeSBoris Brezillon * returned 0.
79967efcaeSBoris Brezillon *
80967efcaeSBoris Brezillon * Return: 0 in case of success, a negative error code otherwise.
81967efcaeSBoris Brezillon */
spi_controller_dma_unmap_mem_op_data(struct spi_controller * ctlr,const struct spi_mem_op * op,struct sg_table * sgt)82967efcaeSBoris Brezillon void spi_controller_dma_unmap_mem_op_data(struct spi_controller *ctlr,
83967efcaeSBoris Brezillon const struct spi_mem_op *op,
84967efcaeSBoris Brezillon struct sg_table *sgt)
85967efcaeSBoris Brezillon {
86967efcaeSBoris Brezillon struct device *dmadev;
87967efcaeSBoris Brezillon
88967efcaeSBoris Brezillon if (!op->data.nbytes)
89967efcaeSBoris Brezillon return;
90967efcaeSBoris Brezillon
91967efcaeSBoris Brezillon if (op->data.dir == SPI_MEM_DATA_OUT && ctlr->dma_tx)
92967efcaeSBoris Brezillon dmadev = ctlr->dma_tx->device->dev;
93967efcaeSBoris Brezillon else if (op->data.dir == SPI_MEM_DATA_IN && ctlr->dma_rx)
94967efcaeSBoris Brezillon dmadev = ctlr->dma_rx->device->dev;
95967efcaeSBoris Brezillon else
96967efcaeSBoris Brezillon dmadev = ctlr->dev.parent;
97967efcaeSBoris Brezillon
98967efcaeSBoris Brezillon spi_unmap_buf(ctlr, dmadev, sgt,
99967efcaeSBoris Brezillon op->data.dir == SPI_MEM_DATA_IN ?
100967efcaeSBoris Brezillon DMA_FROM_DEVICE : DMA_TO_DEVICE);
101967efcaeSBoris Brezillon }
102967efcaeSBoris Brezillon EXPORT_SYMBOL_GPL(spi_controller_dma_unmap_mem_op_data);
103967efcaeSBoris Brezillon #endif /* __UBOOT__ */
104967efcaeSBoris Brezillon
spi_check_buswidth_req(struct spi_slave * slave,u8 buswidth,bool tx)105967efcaeSBoris Brezillon static int spi_check_buswidth_req(struct spi_slave *slave, u8 buswidth, bool tx)
106967efcaeSBoris Brezillon {
107967efcaeSBoris Brezillon u32 mode = slave->mode;
108967efcaeSBoris Brezillon
109967efcaeSBoris Brezillon switch (buswidth) {
110967efcaeSBoris Brezillon case 1:
111967efcaeSBoris Brezillon return 0;
112967efcaeSBoris Brezillon
113967efcaeSBoris Brezillon case 2:
114967efcaeSBoris Brezillon if ((tx && (mode & (SPI_TX_DUAL | SPI_TX_QUAD))) ||
115967efcaeSBoris Brezillon (!tx && (mode & (SPI_RX_DUAL | SPI_RX_QUAD))))
116967efcaeSBoris Brezillon return 0;
117967efcaeSBoris Brezillon
118967efcaeSBoris Brezillon break;
119967efcaeSBoris Brezillon
120967efcaeSBoris Brezillon case 4:
121967efcaeSBoris Brezillon if ((tx && (mode & SPI_TX_QUAD)) ||
122967efcaeSBoris Brezillon (!tx && (mode & SPI_RX_QUAD)))
123967efcaeSBoris Brezillon return 0;
124967efcaeSBoris Brezillon
125967efcaeSBoris Brezillon break;
126*305d7e6eSVignesh Raghavendra case 8:
127*305d7e6eSVignesh Raghavendra if ((tx && (mode & SPI_TX_OCTAL)) ||
128*305d7e6eSVignesh Raghavendra (!tx && (mode & SPI_RX_OCTAL)))
129*305d7e6eSVignesh Raghavendra return 0;
130*305d7e6eSVignesh Raghavendra
131*305d7e6eSVignesh Raghavendra break;
132967efcaeSBoris Brezillon
133967efcaeSBoris Brezillon default:
134967efcaeSBoris Brezillon break;
135967efcaeSBoris Brezillon }
136967efcaeSBoris Brezillon
137967efcaeSBoris Brezillon return -ENOTSUPP;
138967efcaeSBoris Brezillon }
139967efcaeSBoris Brezillon
spi_mem_default_supports_op(struct spi_slave * slave,const struct spi_mem_op * op)140967efcaeSBoris Brezillon bool spi_mem_default_supports_op(struct spi_slave *slave,
141967efcaeSBoris Brezillon const struct spi_mem_op *op)
142967efcaeSBoris Brezillon {
143967efcaeSBoris Brezillon if (spi_check_buswidth_req(slave, op->cmd.buswidth, true))
144967efcaeSBoris Brezillon return false;
145967efcaeSBoris Brezillon
146967efcaeSBoris Brezillon if (op->addr.nbytes &&
147967efcaeSBoris Brezillon spi_check_buswidth_req(slave, op->addr.buswidth, true))
148967efcaeSBoris Brezillon return false;
149967efcaeSBoris Brezillon
150967efcaeSBoris Brezillon if (op->dummy.nbytes &&
151967efcaeSBoris Brezillon spi_check_buswidth_req(slave, op->dummy.buswidth, true))
152967efcaeSBoris Brezillon return false;
153967efcaeSBoris Brezillon
154967efcaeSBoris Brezillon if (op->data.nbytes &&
155967efcaeSBoris Brezillon spi_check_buswidth_req(slave, op->data.buswidth,
156967efcaeSBoris Brezillon op->data.dir == SPI_MEM_DATA_OUT))
157967efcaeSBoris Brezillon return false;
158967efcaeSBoris Brezillon
159967efcaeSBoris Brezillon return true;
160967efcaeSBoris Brezillon }
161967efcaeSBoris Brezillon EXPORT_SYMBOL_GPL(spi_mem_default_supports_op);
162967efcaeSBoris Brezillon
163967efcaeSBoris Brezillon /**
164967efcaeSBoris Brezillon * spi_mem_supports_op() - Check if a memory device and the controller it is
165967efcaeSBoris Brezillon * connected to support a specific memory operation
166967efcaeSBoris Brezillon * @slave: the SPI device
167967efcaeSBoris Brezillon * @op: the memory operation to check
168967efcaeSBoris Brezillon *
169967efcaeSBoris Brezillon * Some controllers are only supporting Single or Dual IOs, others might only
170967efcaeSBoris Brezillon * support specific opcodes, or it can even be that the controller and device
171967efcaeSBoris Brezillon * both support Quad IOs but the hardware prevents you from using it because
172967efcaeSBoris Brezillon * only 2 IO lines are connected.
173967efcaeSBoris Brezillon *
174967efcaeSBoris Brezillon * This function checks whether a specific operation is supported.
175967efcaeSBoris Brezillon *
176967efcaeSBoris Brezillon * Return: true if @op is supported, false otherwise.
177967efcaeSBoris Brezillon */
spi_mem_supports_op(struct spi_slave * slave,const struct spi_mem_op * op)178967efcaeSBoris Brezillon bool spi_mem_supports_op(struct spi_slave *slave,
179967efcaeSBoris Brezillon const struct spi_mem_op *op)
180967efcaeSBoris Brezillon {
181967efcaeSBoris Brezillon struct udevice *bus = slave->dev->parent;
182967efcaeSBoris Brezillon struct dm_spi_ops *ops = spi_get_ops(bus);
183967efcaeSBoris Brezillon
184967efcaeSBoris Brezillon if (ops->mem_ops && ops->mem_ops->supports_op)
185967efcaeSBoris Brezillon return ops->mem_ops->supports_op(slave, op);
186967efcaeSBoris Brezillon
187967efcaeSBoris Brezillon return spi_mem_default_supports_op(slave, op);
188967efcaeSBoris Brezillon }
189967efcaeSBoris Brezillon EXPORT_SYMBOL_GPL(spi_mem_supports_op);
190967efcaeSBoris Brezillon
191967efcaeSBoris Brezillon /**
192967efcaeSBoris Brezillon * spi_mem_exec_op() - Execute a memory operation
193967efcaeSBoris Brezillon * @slave: the SPI device
194967efcaeSBoris Brezillon * @op: the memory operation to execute
195967efcaeSBoris Brezillon *
196967efcaeSBoris Brezillon * Executes a memory operation.
197967efcaeSBoris Brezillon *
198967efcaeSBoris Brezillon * This function first checks that @op is supported and then tries to execute
199967efcaeSBoris Brezillon * it.
200967efcaeSBoris Brezillon *
201967efcaeSBoris Brezillon * Return: 0 in case of success, a negative error code otherwise.
202967efcaeSBoris Brezillon */
spi_mem_exec_op(struct spi_slave * slave,const struct spi_mem_op * op)203967efcaeSBoris Brezillon int spi_mem_exec_op(struct spi_slave *slave, const struct spi_mem_op *op)
204967efcaeSBoris Brezillon {
205967efcaeSBoris Brezillon struct udevice *bus = slave->dev->parent;
206967efcaeSBoris Brezillon struct dm_spi_ops *ops = spi_get_ops(bus);
207967efcaeSBoris Brezillon unsigned int pos = 0;
208967efcaeSBoris Brezillon const u8 *tx_buf = NULL;
209967efcaeSBoris Brezillon u8 *rx_buf = NULL;
210967efcaeSBoris Brezillon int op_len;
211967efcaeSBoris Brezillon u32 flag;
212967efcaeSBoris Brezillon int ret;
213967efcaeSBoris Brezillon int i;
214967efcaeSBoris Brezillon
215967efcaeSBoris Brezillon if (!spi_mem_supports_op(slave, op))
216967efcaeSBoris Brezillon return -ENOTSUPP;
217967efcaeSBoris Brezillon
21883e21979SVignesh R ret = spi_claim_bus(slave);
21983e21979SVignesh R if (ret < 0)
22083e21979SVignesh R return ret;
22183e21979SVignesh R
2223dc0a5efSBernhard Messerklinger if (ops->mem_ops && ops->mem_ops->exec_op) {
223967efcaeSBoris Brezillon #ifndef __UBOOT__
224967efcaeSBoris Brezillon /*
225967efcaeSBoris Brezillon * Flush the message queue before executing our SPI memory
226967efcaeSBoris Brezillon * operation to prevent preemption of regular SPI transfers.
227967efcaeSBoris Brezillon */
228967efcaeSBoris Brezillon spi_flush_queue(ctlr);
229967efcaeSBoris Brezillon
230967efcaeSBoris Brezillon if (ctlr->auto_runtime_pm) {
231967efcaeSBoris Brezillon ret = pm_runtime_get_sync(ctlr->dev.parent);
232967efcaeSBoris Brezillon if (ret < 0) {
233967efcaeSBoris Brezillon dev_err(&ctlr->dev,
234967efcaeSBoris Brezillon "Failed to power device: %d\n",
235967efcaeSBoris Brezillon ret);
236967efcaeSBoris Brezillon return ret;
237967efcaeSBoris Brezillon }
238967efcaeSBoris Brezillon }
239967efcaeSBoris Brezillon
240967efcaeSBoris Brezillon mutex_lock(&ctlr->bus_lock_mutex);
241967efcaeSBoris Brezillon mutex_lock(&ctlr->io_mutex);
242967efcaeSBoris Brezillon #endif
243967efcaeSBoris Brezillon ret = ops->mem_ops->exec_op(slave, op);
24483e21979SVignesh R
245967efcaeSBoris Brezillon #ifndef __UBOOT__
246967efcaeSBoris Brezillon mutex_unlock(&ctlr->io_mutex);
247967efcaeSBoris Brezillon mutex_unlock(&ctlr->bus_lock_mutex);
248967efcaeSBoris Brezillon
249967efcaeSBoris Brezillon if (ctlr->auto_runtime_pm)
250967efcaeSBoris Brezillon pm_runtime_put(ctlr->dev.parent);
251967efcaeSBoris Brezillon #endif
252967efcaeSBoris Brezillon
253967efcaeSBoris Brezillon /*
254967efcaeSBoris Brezillon * Some controllers only optimize specific paths (typically the
255967efcaeSBoris Brezillon * read path) and expect the core to use the regular SPI
256967efcaeSBoris Brezillon * interface in other cases.
257967efcaeSBoris Brezillon */
25883e21979SVignesh R if (!ret || ret != -ENOTSUPP) {
25983e21979SVignesh R spi_release_bus(slave);
260967efcaeSBoris Brezillon return ret;
261967efcaeSBoris Brezillon }
26283e21979SVignesh R }
263967efcaeSBoris Brezillon
264967efcaeSBoris Brezillon #ifndef __UBOOT__
265967efcaeSBoris Brezillon tmpbufsize = sizeof(op->cmd.opcode) + op->addr.nbytes +
266967efcaeSBoris Brezillon op->dummy.nbytes;
267967efcaeSBoris Brezillon
268967efcaeSBoris Brezillon /*
269967efcaeSBoris Brezillon * Allocate a buffer to transmit the CMD, ADDR cycles with kmalloc() so
270967efcaeSBoris Brezillon * we're guaranteed that this buffer is DMA-able, as required by the
271967efcaeSBoris Brezillon * SPI layer.
272967efcaeSBoris Brezillon */
273967efcaeSBoris Brezillon tmpbuf = kzalloc(tmpbufsize, GFP_KERNEL | GFP_DMA);
274967efcaeSBoris Brezillon if (!tmpbuf)
275967efcaeSBoris Brezillon return -ENOMEM;
276967efcaeSBoris Brezillon
277967efcaeSBoris Brezillon spi_message_init(&msg);
278967efcaeSBoris Brezillon
279967efcaeSBoris Brezillon tmpbuf[0] = op->cmd.opcode;
280967efcaeSBoris Brezillon xfers[xferpos].tx_buf = tmpbuf;
281967efcaeSBoris Brezillon xfers[xferpos].len = sizeof(op->cmd.opcode);
282967efcaeSBoris Brezillon xfers[xferpos].tx_nbits = op->cmd.buswidth;
283967efcaeSBoris Brezillon spi_message_add_tail(&xfers[xferpos], &msg);
284967efcaeSBoris Brezillon xferpos++;
285967efcaeSBoris Brezillon totalxferlen++;
286967efcaeSBoris Brezillon
287967efcaeSBoris Brezillon if (op->addr.nbytes) {
288967efcaeSBoris Brezillon int i;
289967efcaeSBoris Brezillon
290967efcaeSBoris Brezillon for (i = 0; i < op->addr.nbytes; i++)
291967efcaeSBoris Brezillon tmpbuf[i + 1] = op->addr.val >>
292967efcaeSBoris Brezillon (8 * (op->addr.nbytes - i - 1));
293967efcaeSBoris Brezillon
294967efcaeSBoris Brezillon xfers[xferpos].tx_buf = tmpbuf + 1;
295967efcaeSBoris Brezillon xfers[xferpos].len = op->addr.nbytes;
296967efcaeSBoris Brezillon xfers[xferpos].tx_nbits = op->addr.buswidth;
297967efcaeSBoris Brezillon spi_message_add_tail(&xfers[xferpos], &msg);
298967efcaeSBoris Brezillon xferpos++;
299967efcaeSBoris Brezillon totalxferlen += op->addr.nbytes;
300967efcaeSBoris Brezillon }
301967efcaeSBoris Brezillon
302967efcaeSBoris Brezillon if (op->dummy.nbytes) {
303967efcaeSBoris Brezillon memset(tmpbuf + op->addr.nbytes + 1, 0xff, op->dummy.nbytes);
304967efcaeSBoris Brezillon xfers[xferpos].tx_buf = tmpbuf + op->addr.nbytes + 1;
305967efcaeSBoris Brezillon xfers[xferpos].len = op->dummy.nbytes;
306967efcaeSBoris Brezillon xfers[xferpos].tx_nbits = op->dummy.buswidth;
307967efcaeSBoris Brezillon spi_message_add_tail(&xfers[xferpos], &msg);
308967efcaeSBoris Brezillon xferpos++;
309967efcaeSBoris Brezillon totalxferlen += op->dummy.nbytes;
310967efcaeSBoris Brezillon }
311967efcaeSBoris Brezillon
312967efcaeSBoris Brezillon if (op->data.nbytes) {
313967efcaeSBoris Brezillon if (op->data.dir == SPI_MEM_DATA_IN) {
314967efcaeSBoris Brezillon xfers[xferpos].rx_buf = op->data.buf.in;
315967efcaeSBoris Brezillon xfers[xferpos].rx_nbits = op->data.buswidth;
316967efcaeSBoris Brezillon } else {
317967efcaeSBoris Brezillon xfers[xferpos].tx_buf = op->data.buf.out;
318967efcaeSBoris Brezillon xfers[xferpos].tx_nbits = op->data.buswidth;
319967efcaeSBoris Brezillon }
320967efcaeSBoris Brezillon
321967efcaeSBoris Brezillon xfers[xferpos].len = op->data.nbytes;
322967efcaeSBoris Brezillon spi_message_add_tail(&xfers[xferpos], &msg);
323967efcaeSBoris Brezillon xferpos++;
324967efcaeSBoris Brezillon totalxferlen += op->data.nbytes;
325967efcaeSBoris Brezillon }
326967efcaeSBoris Brezillon
327967efcaeSBoris Brezillon ret = spi_sync(slave, &msg);
328967efcaeSBoris Brezillon
329967efcaeSBoris Brezillon kfree(tmpbuf);
330967efcaeSBoris Brezillon
331967efcaeSBoris Brezillon if (ret)
332967efcaeSBoris Brezillon return ret;
333967efcaeSBoris Brezillon
334967efcaeSBoris Brezillon if (msg.actual_length != totalxferlen)
335967efcaeSBoris Brezillon return -EIO;
336967efcaeSBoris Brezillon #else
337967efcaeSBoris Brezillon
338967efcaeSBoris Brezillon if (op->data.nbytes) {
339967efcaeSBoris Brezillon if (op->data.dir == SPI_MEM_DATA_IN)
340967efcaeSBoris Brezillon rx_buf = op->data.buf.in;
341967efcaeSBoris Brezillon else
342967efcaeSBoris Brezillon tx_buf = op->data.buf.out;
343967efcaeSBoris Brezillon }
344967efcaeSBoris Brezillon
345967efcaeSBoris Brezillon op_len = sizeof(op->cmd.opcode) + op->addr.nbytes + op->dummy.nbytes;
3466cc5f5ccSSimon Glass
3476cc5f5ccSSimon Glass /*
3486cc5f5ccSSimon Glass * Avoid using malloc() here so that we can use this code in SPL where
3496cc5f5ccSSimon Glass * simple malloc may be used. That implementation does not allow free()
3506cc5f5ccSSimon Glass * so repeated calls to this code can exhaust the space.
3516cc5f5ccSSimon Glass *
3526cc5f5ccSSimon Glass * The value of op_len is small, since it does not include the actual
3536cc5f5ccSSimon Glass * data being sent, only the op-code and address. In fact, it should be
3546cc5f5ccSSimon Glass * possible to just use a small fixed value here instead of op_len.
3556cc5f5ccSSimon Glass */
3566cc5f5ccSSimon Glass u8 op_buf[op_len];
357967efcaeSBoris Brezillon
358967efcaeSBoris Brezillon op_buf[pos++] = op->cmd.opcode;
359967efcaeSBoris Brezillon
360967efcaeSBoris Brezillon if (op->addr.nbytes) {
361967efcaeSBoris Brezillon for (i = 0; i < op->addr.nbytes; i++)
362967efcaeSBoris Brezillon op_buf[pos + i] = op->addr.val >>
363967efcaeSBoris Brezillon (8 * (op->addr.nbytes - i - 1));
364967efcaeSBoris Brezillon
365967efcaeSBoris Brezillon pos += op->addr.nbytes;
366967efcaeSBoris Brezillon }
367967efcaeSBoris Brezillon
368967efcaeSBoris Brezillon if (op->dummy.nbytes)
369967efcaeSBoris Brezillon memset(op_buf + pos, 0xff, op->dummy.nbytes);
370967efcaeSBoris Brezillon
371967efcaeSBoris Brezillon /* 1st transfer: opcode + address + dummy cycles */
372967efcaeSBoris Brezillon flag = SPI_XFER_BEGIN;
373967efcaeSBoris Brezillon /* Make sure to set END bit if no tx or rx data messages follow */
374967efcaeSBoris Brezillon if (!tx_buf && !rx_buf)
375967efcaeSBoris Brezillon flag |= SPI_XFER_END;
376967efcaeSBoris Brezillon
377967efcaeSBoris Brezillon ret = spi_xfer(slave, op_len * 8, op_buf, NULL, flag);
378967efcaeSBoris Brezillon if (ret)
379967efcaeSBoris Brezillon return ret;
380967efcaeSBoris Brezillon
381967efcaeSBoris Brezillon /* 2nd transfer: rx or tx data path */
382967efcaeSBoris Brezillon if (tx_buf || rx_buf) {
383f5a32af5SJon Lin flag = SPI_XFER_END;
384f5a32af5SJon Lin if (slave->mode & SPI_DMA_PREPARE)
385f5a32af5SJon Lin flag |= SPI_XFER_PREPARE;
386f5a32af5SJon Lin
387967efcaeSBoris Brezillon ret = spi_xfer(slave, op->data.nbytes * 8, tx_buf,
388f5a32af5SJon Lin rx_buf, flag);
389967efcaeSBoris Brezillon if (ret)
390967efcaeSBoris Brezillon return ret;
391967efcaeSBoris Brezillon }
392967efcaeSBoris Brezillon
393967efcaeSBoris Brezillon spi_release_bus(slave);
394967efcaeSBoris Brezillon
395967efcaeSBoris Brezillon for (i = 0; i < pos; i++)
396967efcaeSBoris Brezillon debug("%02x ", op_buf[i]);
397967efcaeSBoris Brezillon debug("| [%dB %s] ",
398967efcaeSBoris Brezillon tx_buf || rx_buf ? op->data.nbytes : 0,
399967efcaeSBoris Brezillon tx_buf || rx_buf ? (tx_buf ? "out" : "in") : "-");
400967efcaeSBoris Brezillon for (i = 0; i < op->data.nbytes; i++)
401967efcaeSBoris Brezillon debug("%02x ", tx_buf ? tx_buf[i] : rx_buf[i]);
402967efcaeSBoris Brezillon debug("[ret %d]\n", ret);
403967efcaeSBoris Brezillon
404967efcaeSBoris Brezillon if (ret < 0)
405967efcaeSBoris Brezillon return ret;
406967efcaeSBoris Brezillon #endif /* __UBOOT__ */
407967efcaeSBoris Brezillon
408967efcaeSBoris Brezillon return 0;
409967efcaeSBoris Brezillon }
410967efcaeSBoris Brezillon EXPORT_SYMBOL_GPL(spi_mem_exec_op);
411967efcaeSBoris Brezillon
412967efcaeSBoris Brezillon /**
413967efcaeSBoris Brezillon * spi_mem_adjust_op_size() - Adjust the data size of a SPI mem operation to
414967efcaeSBoris Brezillon * match controller limitations
415967efcaeSBoris Brezillon * @slave: the SPI device
416967efcaeSBoris Brezillon * @op: the operation to adjust
417967efcaeSBoris Brezillon *
418967efcaeSBoris Brezillon * Some controllers have FIFO limitations and must split a data transfer
419967efcaeSBoris Brezillon * operation into multiple ones, others require a specific alignment for
420967efcaeSBoris Brezillon * optimized accesses. This function allows SPI mem drivers to split a single
421967efcaeSBoris Brezillon * operation into multiple sub-operations when required.
422967efcaeSBoris Brezillon *
423967efcaeSBoris Brezillon * Return: a negative error code if the controller can't properly adjust @op,
424967efcaeSBoris Brezillon * 0 otherwise. Note that @op->data.nbytes will be updated if @op
425967efcaeSBoris Brezillon * can't be handled in a single step.
426967efcaeSBoris Brezillon */
spi_mem_adjust_op_size(struct spi_slave * slave,struct spi_mem_op * op)427967efcaeSBoris Brezillon int spi_mem_adjust_op_size(struct spi_slave *slave, struct spi_mem_op *op)
428967efcaeSBoris Brezillon {
429967efcaeSBoris Brezillon struct udevice *bus = slave->dev->parent;
430967efcaeSBoris Brezillon struct dm_spi_ops *ops = spi_get_ops(bus);
431967efcaeSBoris Brezillon
432967efcaeSBoris Brezillon if (ops->mem_ops && ops->mem_ops->adjust_op_size)
433967efcaeSBoris Brezillon return ops->mem_ops->adjust_op_size(slave, op);
434967efcaeSBoris Brezillon
4353e37766eSVignesh R if (!ops->mem_ops || !ops->mem_ops->exec_op) {
4363e37766eSVignesh R unsigned int len;
4373e37766eSVignesh R
4383e37766eSVignesh R len = sizeof(op->cmd.opcode) + op->addr.nbytes +
4393e37766eSVignesh R op->dummy.nbytes;
4403e37766eSVignesh R if (slave->max_write_size && len > slave->max_write_size)
4413e37766eSVignesh R return -EINVAL;
4423e37766eSVignesh R
4433e37766eSVignesh R if (op->data.dir == SPI_MEM_DATA_IN && slave->max_read_size)
4443e37766eSVignesh R op->data.nbytes = min(op->data.nbytes,
4453e37766eSVignesh R slave->max_read_size);
4463e37766eSVignesh R else if (slave->max_write_size)
4473e37766eSVignesh R op->data.nbytes = min(op->data.nbytes,
4483e37766eSVignesh R slave->max_write_size - len);
4493e37766eSVignesh R
4503e37766eSVignesh R if (!op->data.nbytes)
4513e37766eSVignesh R return -EINVAL;
4523e37766eSVignesh R }
4533e37766eSVignesh R
454967efcaeSBoris Brezillon return 0;
455967efcaeSBoris Brezillon }
456967efcaeSBoris Brezillon EXPORT_SYMBOL_GPL(spi_mem_adjust_op_size);
457967efcaeSBoris Brezillon
458967efcaeSBoris Brezillon #ifndef __UBOOT__
to_spi_mem_drv(struct device_driver * drv)459967efcaeSBoris Brezillon static inline struct spi_mem_driver *to_spi_mem_drv(struct device_driver *drv)
460967efcaeSBoris Brezillon {
461967efcaeSBoris Brezillon return container_of(drv, struct spi_mem_driver, spidrv.driver);
462967efcaeSBoris Brezillon }
463967efcaeSBoris Brezillon
spi_mem_probe(struct spi_device * spi)464967efcaeSBoris Brezillon static int spi_mem_probe(struct spi_device *spi)
465967efcaeSBoris Brezillon {
466967efcaeSBoris Brezillon struct spi_mem_driver *memdrv = to_spi_mem_drv(spi->dev.driver);
467967efcaeSBoris Brezillon struct spi_mem *mem;
468967efcaeSBoris Brezillon
469967efcaeSBoris Brezillon mem = devm_kzalloc(&spi->dev, sizeof(*mem), GFP_KERNEL);
470967efcaeSBoris Brezillon if (!mem)
471967efcaeSBoris Brezillon return -ENOMEM;
472967efcaeSBoris Brezillon
473967efcaeSBoris Brezillon mem->spi = spi;
474967efcaeSBoris Brezillon spi_set_drvdata(spi, mem);
475967efcaeSBoris Brezillon
476967efcaeSBoris Brezillon return memdrv->probe(mem);
477967efcaeSBoris Brezillon }
478967efcaeSBoris Brezillon
spi_mem_remove(struct spi_device * spi)479967efcaeSBoris Brezillon static int spi_mem_remove(struct spi_device *spi)
480967efcaeSBoris Brezillon {
481967efcaeSBoris Brezillon struct spi_mem_driver *memdrv = to_spi_mem_drv(spi->dev.driver);
482967efcaeSBoris Brezillon struct spi_mem *mem = spi_get_drvdata(spi);
483967efcaeSBoris Brezillon
484967efcaeSBoris Brezillon if (memdrv->remove)
485967efcaeSBoris Brezillon return memdrv->remove(mem);
486967efcaeSBoris Brezillon
487967efcaeSBoris Brezillon return 0;
488967efcaeSBoris Brezillon }
489967efcaeSBoris Brezillon
spi_mem_shutdown(struct spi_device * spi)490967efcaeSBoris Brezillon static void spi_mem_shutdown(struct spi_device *spi)
491967efcaeSBoris Brezillon {
492967efcaeSBoris Brezillon struct spi_mem_driver *memdrv = to_spi_mem_drv(spi->dev.driver);
493967efcaeSBoris Brezillon struct spi_mem *mem = spi_get_drvdata(spi);
494967efcaeSBoris Brezillon
495967efcaeSBoris Brezillon if (memdrv->shutdown)
496967efcaeSBoris Brezillon memdrv->shutdown(mem);
497967efcaeSBoris Brezillon }
498967efcaeSBoris Brezillon
499967efcaeSBoris Brezillon /**
500967efcaeSBoris Brezillon * spi_mem_driver_register_with_owner() - Register a SPI memory driver
501967efcaeSBoris Brezillon * @memdrv: the SPI memory driver to register
502967efcaeSBoris Brezillon * @owner: the owner of this driver
503967efcaeSBoris Brezillon *
504967efcaeSBoris Brezillon * Registers a SPI memory driver.
505967efcaeSBoris Brezillon *
506967efcaeSBoris Brezillon * Return: 0 in case of success, a negative error core otherwise.
507967efcaeSBoris Brezillon */
508967efcaeSBoris Brezillon
spi_mem_driver_register_with_owner(struct spi_mem_driver * memdrv,struct module * owner)509967efcaeSBoris Brezillon int spi_mem_driver_register_with_owner(struct spi_mem_driver *memdrv,
510967efcaeSBoris Brezillon struct module *owner)
511967efcaeSBoris Brezillon {
512967efcaeSBoris Brezillon memdrv->spidrv.probe = spi_mem_probe;
513967efcaeSBoris Brezillon memdrv->spidrv.remove = spi_mem_remove;
514967efcaeSBoris Brezillon memdrv->spidrv.shutdown = spi_mem_shutdown;
515967efcaeSBoris Brezillon
516967efcaeSBoris Brezillon return __spi_register_driver(owner, &memdrv->spidrv);
517967efcaeSBoris Brezillon }
518967efcaeSBoris Brezillon EXPORT_SYMBOL_GPL(spi_mem_driver_register_with_owner);
519967efcaeSBoris Brezillon
520967efcaeSBoris Brezillon /**
521967efcaeSBoris Brezillon * spi_mem_driver_unregister_with_owner() - Unregister a SPI memory driver
522967efcaeSBoris Brezillon * @memdrv: the SPI memory driver to unregister
523967efcaeSBoris Brezillon *
524967efcaeSBoris Brezillon * Unregisters a SPI memory driver.
525967efcaeSBoris Brezillon */
spi_mem_driver_unregister(struct spi_mem_driver * memdrv)526967efcaeSBoris Brezillon void spi_mem_driver_unregister(struct spi_mem_driver *memdrv)
527967efcaeSBoris Brezillon {
528967efcaeSBoris Brezillon spi_unregister_driver(&memdrv->spidrv);
529967efcaeSBoris Brezillon }
530967efcaeSBoris Brezillon EXPORT_SYMBOL_GPL(spi_mem_driver_unregister);
531967efcaeSBoris Brezillon #endif /* __UBOOT__ */
532