1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2
3 #include <assert.h>
4 #include <commonlib/helpers.h>
5 #include <spi-generic.h>
6 #include <stddef.h>
7 #include <string.h>
8
spi_claim_bus(const struct spi_slave * slave)9 int spi_claim_bus(const struct spi_slave *slave)
10 {
11 const struct spi_ctrlr *ctrlr = slave->ctrlr;
12 if (ctrlr && ctrlr->claim_bus)
13 return ctrlr->claim_bus(slave);
14 return 0;
15 }
16
spi_release_bus(const struct spi_slave * slave)17 void spi_release_bus(const struct spi_slave *slave)
18 {
19 const struct spi_ctrlr *ctrlr = slave->ctrlr;
20 if (ctrlr && ctrlr->release_bus)
21 ctrlr->release_bus(slave);
22 }
23
spi_xfer_single_op(const struct spi_slave * slave,struct spi_op * op)24 static int spi_xfer_single_op(const struct spi_slave *slave,
25 struct spi_op *op)
26 {
27 const struct spi_ctrlr *ctrlr = slave->ctrlr;
28 int ret;
29
30 if (!ctrlr || !ctrlr->xfer)
31 return -1;
32
33 ret = ctrlr->xfer(slave, op->dout, op->bytesout, op->din, op->bytesin);
34 if (ret)
35 op->status = SPI_OP_FAILURE;
36 else
37 op->status = SPI_OP_SUCCESS;
38
39 return ret;
40 }
41
spi_xfer_vector_default(const struct spi_slave * slave,struct spi_op vectors[],size_t count)42 static int spi_xfer_vector_default(const struct spi_slave *slave,
43 struct spi_op vectors[], size_t count)
44 {
45 size_t i;
46 int ret;
47
48 for (i = 0; i < count; i++) {
49 ret = spi_xfer_single_op(slave, &vectors[i]);
50 if (ret)
51 return ret;
52 }
53
54 return 0;
55 }
56
spi_xfer_vector(const struct spi_slave * slave,struct spi_op vectors[],size_t count)57 int spi_xfer_vector(const struct spi_slave *slave,
58 struct spi_op vectors[], size_t count)
59 {
60 const struct spi_ctrlr *ctrlr = slave->ctrlr;
61
62 if (ctrlr && ctrlr->xfer_vector)
63 return ctrlr->xfer_vector(slave, vectors, count);
64
65 return spi_xfer_vector_default(slave, vectors, count);
66 }
67
spi_xfer(const struct spi_slave * slave,const void * dout,size_t bytesout,void * din,size_t bytesin)68 int spi_xfer(const struct spi_slave *slave, const void *dout, size_t bytesout,
69 void *din, size_t bytesin)
70 {
71 const struct spi_ctrlr *ctrlr = slave->ctrlr;
72
73 if (ctrlr && ctrlr->xfer)
74 return ctrlr->xfer(slave, dout, bytesout, din, bytesin);
75
76 return -1;
77 }
78
spi_crop_chunk(const struct spi_slave * slave,unsigned int cmd_len,unsigned int buf_len)79 unsigned int spi_crop_chunk(const struct spi_slave *slave, unsigned int cmd_len,
80 unsigned int buf_len)
81 {
82 const struct spi_ctrlr *ctrlr = slave->ctrlr;
83 unsigned int ctrlr_max;
84 bool deduct_cmd_len;
85 bool deduct_opcode_len;
86
87 if (!ctrlr)
88 return 0;
89
90 deduct_cmd_len = !!(ctrlr->flags & SPI_CNTRLR_DEDUCT_CMD_LEN);
91 deduct_opcode_len = !!(ctrlr->flags & SPI_CNTRLR_DEDUCT_OPCODE_LEN);
92 ctrlr_max = ctrlr->max_xfer_size;
93
94 assert(ctrlr_max != 0);
95
96 /* Assume opcode is always one byte and deduct it from the cmd_len
97 as the hardware has a separate register for the opcode. */
98 if (deduct_opcode_len)
99 cmd_len--;
100
101 /* Subtract command length from usable buffer size. If
102 deduct_opcode_len is set, only subtract the number command bytes
103 after the opcode. If the adjusted cmd_len is larger than ctrlr_max
104 return 0 to indicate an error. */
105 if (deduct_cmd_len) {
106 if (ctrlr_max >= cmd_len) {
107 ctrlr_max -= cmd_len;
108 } else {
109 ctrlr_max = 0;
110 printk(BIOS_WARNING, "%s: Command longer than buffer\n", __func__);
111 }
112 }
113
114 return MIN(ctrlr_max, buf_len);
115 }
116
spi_init(void)117 void __weak spi_init(void)
118 {
119 /* Default weak implementation - do nothing. */
120 }
121
spi_setup_slave(unsigned int bus,unsigned int cs,struct spi_slave * slave)122 int spi_setup_slave(unsigned int bus, unsigned int cs, struct spi_slave *slave)
123 {
124 size_t i;
125
126 memset(slave, 0, sizeof(*slave));
127
128 for (i = 0; i < spi_ctrlr_bus_map_count; i++) {
129 if ((spi_ctrlr_bus_map[i].bus_start <= bus) &&
130 (spi_ctrlr_bus_map[i].bus_end >= bus)) {
131 slave->ctrlr = spi_ctrlr_bus_map[i].ctrlr;
132 break;
133 }
134 }
135
136 if (slave->ctrlr == NULL) {
137 printk(BIOS_ERR, "Can't find SPI bus %u\n", bus);
138 return -1;
139 }
140
141 slave->bus = bus;
142 slave->cs = cs;
143
144 if (slave->ctrlr->setup)
145 return slave->ctrlr->setup(slave);
146
147 return 0;
148 }
149