blob: c1ecd674677218eee86a4eb6a680f33bf6bda53a [file] [log] [blame]
Patrick Georgiac959032020-05-05 22:49:26 +02001/* SPDX-License-Identifier: GPL-2.0-or-later */
Furquan Shaikh94f86992016-12-01 07:12:32 -08002
Furquan Shaikhc2973d12016-11-29 22:07:42 -08003#include <assert.h>
Elyes HAOUAS361a9352019-12-18 21:26:33 +01004#include <commonlib/helpers.h>
Furquan Shaikh94f86992016-12-01 07:12:32 -08005#include <spi-generic.h>
Elyes HAOUASede8dd02019-06-23 06:57:53 +02006#include <stddef.h>
Furquan Shaikh94f86992016-12-01 07:12:32 -08007#include <string.h>
8
9int 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
17void 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
Furquan Shaikhc2973d12016-11-29 22:07:42 -080024static 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
42static 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
57int 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
Furquan Shaikh94f86992016-12-01 07:12:32 -080068int 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;
Furquan Shaikhc2973d12016-11-29 22:07:42 -080072
Furquan Shaikh94f86992016-12-01 07:12:32 -080073 if (ctrlr && ctrlr->xfer)
74 return ctrlr->xfer(slave, dout, bytesout, din, bytesin);
75
76 return -1;
77}
Furquan Shaikhb5d41cb2016-12-01 07:25:31 -080078
Furquan Shaikhde705fa2017-04-19 19:27:28 -070079unsigned 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;
Aaron Durbin1fcc9f32018-01-29 11:30:17 -070084 bool deduct_cmd_len;
85 bool deduct_opcode_len;
Furquan Shaikhde705fa2017-04-19 19:27:28 -070086
87 if (!ctrlr)
88 return 0;
89
Aaron Durbin1fcc9f32018-01-29 11:30:17 -070090 deduct_cmd_len = !!(ctrlr->flags & SPI_CNTRLR_DEDUCT_CMD_LEN);
91 deduct_opcode_len = !!(ctrlr->flags & SPI_CNTRLR_DEDUCT_OPCODE_LEN);
Furquan Shaikhde705fa2017-04-19 19:27:28 -070092 ctrlr_max = ctrlr->max_xfer_size;
93
94 assert (ctrlr_max != 0);
95
Aaron Durbin1fcc9f32018-01-29 11:30:17 -070096 /* 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
Elyes Haouas7865ce82023-08-26 16:52:56 +0200101 /* Subtract command length from usable buffer size. If
Felix Held55dce1d2021-12-10 18:38:16 +0100102 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 inidicate an error. */
Felix Helde3ae7552021-12-10 18:38:16 +0100105 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 }
Furquan Shaikhde705fa2017-04-19 19:27:28 -0700113
Elyes HAOUAS361a9352019-12-18 21:26:33 +0100114 return MIN(ctrlr_max, buf_len);
Furquan Shaikhde705fa2017-04-19 19:27:28 -0700115}
116
Aaron Durbin64031672018-04-21 14:45:32 -0600117void __weak spi_init(void)
Furquan Shaikhb5d41cb2016-12-01 07:25:31 -0800118{
119 /* Default weak implementation - do nothing. */
120}
121
Furquan Shaikhdd8d2472017-05-18 15:08:51 -0700122int spi_setup_slave(unsigned int bus, unsigned int cs, struct spi_slave *slave)
Furquan Shaikhb5d41cb2016-12-01 07:25:31 -0800123{
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
Julius Wernerc1b98a42021-09-10 19:08:48 -0700136 if (slave->ctrlr == NULL) {
137 printk(BIOS_ERR, "Can't find SPI bus %u\n", bus);
Furquan Shaikhb5d41cb2016-12-01 07:25:31 -0800138 return -1;
Julius Wernerc1b98a42021-09-10 19:08:48 -0700139 }
Furquan Shaikhb5d41cb2016-12-01 07:25:31 -0800140
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}