Prepare v2024.10
[platform/kernel/u-boot.git] / drivers / spi / sandbox_spi.c
1 /*
2  * Simulate a SPI port
3  *
4  * Copyright (c) 2011-2013 The Chromium OS Authors.
5  * See file CREDITS for list of people who contributed to this
6  * project.
7  *
8  * Licensed under the GPL-2 or later.
9  */
10
11 #define LOG_CATEGORY UCLASS_SPI
12
13 #include <dm.h>
14 #include <log.h>
15 #include <malloc.h>
16 #include <spi.h>
17 #include <spi_flash.h>
18 #include <os.h>
19
20 #include <linux/errno.h>
21 #include <asm/spi.h>
22 #include <asm/state.h>
23 #include <dm/acpi.h>
24 #include <dm/device-internal.h>
25
26 /**
27  * struct sandbox_spi_priv - Sandbox SPI private data
28  *
29  * Helper struct to keep track of the sandbox SPI bus internal state. It is
30  * used in unit tests to verify that dm spi functions update the bus
31  * speed/mode properly (for instance, when jumping back and forth between spi
32  * slaves claiming the bus, we need to make sure that the bus speed is updated
33  * accordingly for each slave).
34  *
35  * @speed:      Current bus speed.
36  * @mode:       Current bus mode.
37  */
38 struct sandbox_spi_priv {
39         uint speed;
40         uint mode;
41 };
42
43 __weak int sandbox_spi_get_emul(struct sandbox_state *state,
44                                 struct udevice *bus, struct udevice *slave,
45                                 struct udevice **emulp)
46 {
47         return -ENOENT;
48 }
49
50 uint sandbox_spi_get_speed(struct udevice *dev)
51 {
52         struct sandbox_spi_priv *priv = dev_get_priv(dev);
53
54         return priv->speed;
55 }
56
57 uint sandbox_spi_get_mode(struct udevice *dev)
58 {
59         struct sandbox_spi_priv *priv = dev_get_priv(dev);
60
61         return priv->mode;
62 }
63
64 static int sandbox_spi_xfer(struct udevice *slave, unsigned int bitlen,
65                             const void *dout, void *din, unsigned long flags)
66 {
67         struct udevice *bus = slave->parent;
68         struct sandbox_state *state = state_get_current();
69         struct dm_spi_emul_ops *ops;
70         struct udevice *emul;
71         uint bytes = bitlen / 8, i;
72         int ret;
73         uint busnum, cs;
74
75         if (bitlen == 0)
76                 return 0;
77
78         /* we can only do 8 bit transfers */
79         if (bitlen % 8) {
80                 printf("sandbox_spi: xfer: invalid bitlen size %u; needs to be 8bit\n",
81                        bitlen);
82                 return -EINVAL;
83         }
84
85         busnum = dev_seq(bus);
86         cs = spi_chip_select(slave);
87         if (busnum >= CONFIG_SANDBOX_SPI_MAX_BUS ||
88             cs >= CONFIG_SANDBOX_SPI_MAX_CS) {
89                 printf("%s: busnum=%u, cs=%u: out of range\n", __func__,
90                        busnum, cs);
91                 return -ENOENT;
92         }
93         ret = sandbox_spi_get_emul(state, bus, slave, &emul);
94         if (ret) {
95                 printf("%s: busnum=%u, cs=%u: no emulation available (err=%d)\n",
96                        __func__, busnum, cs, ret);
97                 return -ENOENT;
98         }
99         ret = device_probe(emul);
100         if (ret)
101                 return ret;
102
103         ops = spi_emul_get_ops(emul);
104         ret = ops->xfer(emul, bitlen, dout, din, flags);
105
106         log_content("sandbox_spi: xfer: got back %i (that's %s)\n rx:",
107                     ret, ret ? "bad" : "good");
108         if (din) {
109                 for (i = 0; i < bytes; ++i)
110                         log_content(" %u:%02x", i, ((u8 *)din)[i]);
111         }
112         log_content("\n");
113
114         return ret;
115 }
116
117 static int sandbox_spi_set_speed(struct udevice *bus, uint speed)
118 {
119         struct sandbox_spi_priv *priv = dev_get_priv(bus);
120
121         priv->speed = speed;
122
123         return 0;
124 }
125
126 static int sandbox_spi_set_mode(struct udevice *bus, uint mode)
127 {
128         struct sandbox_spi_priv *priv = dev_get_priv(bus);
129
130         priv->mode = mode;
131
132         return 0;
133 }
134
135 static int sandbox_cs_info(struct udevice *bus, uint cs,
136                            struct spi_cs_info *info)
137 {
138         /* Always allow activity on CS 0, CS 1 */
139         if (cs >= 2)
140                 return -EINVAL;
141
142         return 0;
143 }
144
145 static int sandbox_spi_get_mmap(struct udevice *dev, ulong *map_basep,
146                                 uint *map_sizep, uint *offsetp)
147 {
148         *map_basep = 0x1000;
149         *map_sizep = 0x2000;
150         *offsetp = 0x100;
151
152         return 0;
153 }
154
155 static const struct dm_spi_ops sandbox_spi_ops = {
156         .xfer           = sandbox_spi_xfer,
157         .set_speed      = sandbox_spi_set_speed,
158         .set_mode       = sandbox_spi_set_mode,
159         .cs_info        = sandbox_cs_info,
160         .get_mmap       = sandbox_spi_get_mmap,
161 };
162
163 static const struct udevice_id sandbox_spi_ids[] = {
164         { .compatible = "sandbox,spi" },
165         { }
166 };
167
168 U_BOOT_DRIVER(sandbox_spi) = {
169         .name   = "sandbox_spi",
170         .id     = UCLASS_SPI,
171         .of_match = sandbox_spi_ids,
172         .ops    = &sandbox_spi_ops,
173         .priv_auto = sizeof(struct sandbox_spi_priv),
174 };