xref: /OK3568_Linux_fs/u-boot/drivers/spi/spi-mem-nodm.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
4*4882a593Smuzhiyun  */
5*4882a593Smuzhiyun 
6*4882a593Smuzhiyun #include <spi.h>
7*4882a593Smuzhiyun #include <spi-mem.h>
8*4882a593Smuzhiyun 
spi_mem_exec_op(struct spi_slave * slave,const struct spi_mem_op * op)9*4882a593Smuzhiyun int spi_mem_exec_op(struct spi_slave *slave,
10*4882a593Smuzhiyun 		    const struct spi_mem_op *op)
11*4882a593Smuzhiyun {
12*4882a593Smuzhiyun 	unsigned int pos = 0;
13*4882a593Smuzhiyun 	const u8 *tx_buf = NULL;
14*4882a593Smuzhiyun 	u8 *rx_buf = NULL;
15*4882a593Smuzhiyun 	u8 *op_buf;
16*4882a593Smuzhiyun 	int op_len;
17*4882a593Smuzhiyun 	u32 flag;
18*4882a593Smuzhiyun 	int ret;
19*4882a593Smuzhiyun 	int i;
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun 	if (op->data.nbytes) {
22*4882a593Smuzhiyun 		if (op->data.dir == SPI_MEM_DATA_IN)
23*4882a593Smuzhiyun 			rx_buf = op->data.buf.in;
24*4882a593Smuzhiyun 		else
25*4882a593Smuzhiyun 			tx_buf = op->data.buf.out;
26*4882a593Smuzhiyun 	}
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun 	op_len = sizeof(op->cmd.opcode) + op->addr.nbytes + op->dummy.nbytes;
29*4882a593Smuzhiyun 	op_buf = calloc(1, op_len);
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun 	ret = spi_claim_bus(slave);
32*4882a593Smuzhiyun 	if (ret < 0)
33*4882a593Smuzhiyun 		return ret;
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun 	op_buf[pos++] = op->cmd.opcode;
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun 	if (op->addr.nbytes) {
38*4882a593Smuzhiyun 		for (i = 0; i < op->addr.nbytes; i++)
39*4882a593Smuzhiyun 			op_buf[pos + i] = op->addr.val >>
40*4882a593Smuzhiyun 				(8 * (op->addr.nbytes - i - 1));
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun 		pos += op->addr.nbytes;
43*4882a593Smuzhiyun 	}
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun 	if (op->dummy.nbytes)
46*4882a593Smuzhiyun 		memset(op_buf + pos, 0xff, op->dummy.nbytes);
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun 	/* 1st transfer: opcode + address + dummy cycles */
49*4882a593Smuzhiyun 	flag = SPI_XFER_BEGIN;
50*4882a593Smuzhiyun 	/* Make sure to set END bit if no tx or rx data messages follow */
51*4882a593Smuzhiyun 	if (!tx_buf && !rx_buf)
52*4882a593Smuzhiyun 		flag |= SPI_XFER_END;
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun 	ret = spi_xfer(slave, op_len * 8, op_buf, NULL, flag);
55*4882a593Smuzhiyun 	if (ret)
56*4882a593Smuzhiyun 		return ret;
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun 	/* 2nd transfer: rx or tx data path */
59*4882a593Smuzhiyun 	if (tx_buf || rx_buf) {
60*4882a593Smuzhiyun 		ret = spi_xfer(slave, op->data.nbytes * 8, tx_buf,
61*4882a593Smuzhiyun 			       rx_buf, SPI_XFER_END);
62*4882a593Smuzhiyun 		if (ret)
63*4882a593Smuzhiyun 			return ret;
64*4882a593Smuzhiyun 	}
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun 	spi_release_bus(slave);
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun 	for (i = 0; i < pos; i++)
69*4882a593Smuzhiyun 		debug("%02x ", op_buf[i]);
70*4882a593Smuzhiyun 	debug("| [%dB %s] ",
71*4882a593Smuzhiyun 	      tx_buf || rx_buf ? op->data.nbytes : 0,
72*4882a593Smuzhiyun 	      tx_buf || rx_buf ? (tx_buf ? "out" : "in") : "-");
73*4882a593Smuzhiyun 	for (i = 0; i < op->data.nbytes; i++)
74*4882a593Smuzhiyun 		debug("%02x ", tx_buf ? tx_buf[i] : rx_buf[i]);
75*4882a593Smuzhiyun 	debug("[ret %d]\n", ret);
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun 	free(op_buf);
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 	if (ret < 0)
80*4882a593Smuzhiyun 		return ret;
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun 	return 0;
83*4882a593Smuzhiyun }
84*4882a593Smuzhiyun 
spi_mem_adjust_op_size(struct spi_slave * slave,struct spi_mem_op * op)85*4882a593Smuzhiyun int spi_mem_adjust_op_size(struct spi_slave *slave,
86*4882a593Smuzhiyun 			   struct spi_mem_op *op)
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun 	unsigned int len;
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 	len = sizeof(op->cmd.opcode) + op->addr.nbytes + op->dummy.nbytes;
91*4882a593Smuzhiyun 	if (slave->max_write_size && len > slave->max_write_size)
92*4882a593Smuzhiyun 		return -EINVAL;
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 	if (op->data.dir == SPI_MEM_DATA_IN && slave->max_read_size)
95*4882a593Smuzhiyun 		op->data.nbytes = min(op->data.nbytes,
96*4882a593Smuzhiyun 				      slave->max_read_size);
97*4882a593Smuzhiyun 	else if (slave->max_write_size)
98*4882a593Smuzhiyun 		op->data.nbytes = min(op->data.nbytes,
99*4882a593Smuzhiyun 				      slave->max_write_size - len);
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun 	if (!op->data.nbytes)
102*4882a593Smuzhiyun 		return -EINVAL;
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun 	return 0;
105*4882a593Smuzhiyun }
106