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 #include <common.h> 12 #include <malloc.h> 13 #include <spi.h> 14 #include <os.h> 15 16 #include <asm/errno.h> 17 #include <asm/spi.h> 18 #include <asm/state.h> 19 20 #ifndef CONFIG_SPI_IDLE_VAL 21 # define CONFIG_SPI_IDLE_VAL 0xFF 22 #endif 23 24 struct sandbox_spi_slave { 25 struct spi_slave slave; 26 const struct sandbox_spi_emu_ops *ops; 27 void *priv; 28 }; 29 30 #define to_sandbox_spi_slave(s) container_of(s, struct sandbox_spi_slave, slave) 31 32 const char *sandbox_spi_parse_spec(const char *arg, unsigned long *bus, 33 unsigned long *cs) 34 { 35 char *endp; 36 37 *bus = simple_strtoul(arg, &endp, 0); 38 if (*endp != ':' || *bus >= CONFIG_SANDBOX_SPI_MAX_BUS) 39 return NULL; 40 41 *cs = simple_strtoul(endp + 1, &endp, 0); 42 if (*endp != ':' || *cs >= CONFIG_SANDBOX_SPI_MAX_CS) 43 return NULL; 44 45 return endp + 1; 46 } 47 48 int spi_cs_is_valid(unsigned int bus, unsigned int cs) 49 { 50 return bus < CONFIG_SANDBOX_SPI_MAX_BUS && 51 cs < CONFIG_SANDBOX_SPI_MAX_CS; 52 } 53 54 void spi_cs_activate(struct spi_slave *slave) 55 { 56 struct sandbox_spi_slave *sss = to_sandbox_spi_slave(slave); 57 58 debug("sandbox_spi: activating CS\n"); 59 if (sss->ops->cs_activate) 60 sss->ops->cs_activate(sss->priv); 61 } 62 63 void spi_cs_deactivate(struct spi_slave *slave) 64 { 65 struct sandbox_spi_slave *sss = to_sandbox_spi_slave(slave); 66 67 debug("sandbox_spi: deactivating CS\n"); 68 if (sss->ops->cs_deactivate) 69 sss->ops->cs_deactivate(sss->priv); 70 } 71 72 void spi_init(void) 73 { 74 } 75 76 void spi_set_speed(struct spi_slave *slave, uint hz) 77 { 78 } 79 80 struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, 81 unsigned int max_hz, unsigned int mode) 82 { 83 struct sandbox_spi_slave *sss; 84 struct sandbox_state *state = state_get_current(); 85 const char *spec; 86 87 if (!spi_cs_is_valid(bus, cs)) { 88 debug("sandbox_spi: Invalid SPI bus/cs\n"); 89 return NULL; 90 } 91 92 sss = spi_alloc_slave(struct sandbox_spi_slave, bus, cs); 93 if (!sss) { 94 debug("sandbox_spi: Out of memory\n"); 95 return NULL; 96 } 97 98 spec = state->spi[bus][cs].spec; 99 sss->ops = state->spi[bus][cs].ops; 100 if (!spec || !sss->ops || sss->ops->setup(&sss->priv, spec)) { 101 free(sss); 102 printf("sandbox_spi: unable to locate a slave client\n"); 103 return NULL; 104 } 105 106 return &sss->slave; 107 } 108 109 void spi_free_slave(struct spi_slave *slave) 110 { 111 struct sandbox_spi_slave *sss = to_sandbox_spi_slave(slave); 112 113 debug("sandbox_spi: releasing slave\n"); 114 115 if (sss->ops->free) 116 sss->ops->free(sss->priv); 117 118 free(sss); 119 } 120 121 static int spi_bus_claim_cnt[CONFIG_SANDBOX_SPI_MAX_BUS]; 122 123 int spi_claim_bus(struct spi_slave *slave) 124 { 125 if (spi_bus_claim_cnt[slave->bus]++) { 126 printf("sandbox_spi: error: bus already claimed: %d!\n", 127 spi_bus_claim_cnt[slave->bus]); 128 } 129 130 return 0; 131 } 132 133 void spi_release_bus(struct spi_slave *slave) 134 { 135 if (--spi_bus_claim_cnt[slave->bus]) { 136 printf("sandbox_spi: error: bus freed too often: %d!\n", 137 spi_bus_claim_cnt[slave->bus]); 138 } 139 } 140 141 int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, 142 void *din, unsigned long flags) 143 { 144 struct sandbox_spi_slave *sss = to_sandbox_spi_slave(slave); 145 uint bytes = bitlen / 8, i; 146 int ret = 0; 147 u8 *tx = (void *)dout, *rx = din; 148 149 if (bitlen == 0) 150 goto done; 151 152 /* we can only do 8 bit transfers */ 153 if (bitlen % 8) { 154 printf("sandbox_spi: xfer: invalid bitlen size %u; needs to be 8bit\n", 155 bitlen); 156 flags |= SPI_XFER_END; 157 goto done; 158 } 159 160 if (flags & SPI_XFER_BEGIN) 161 spi_cs_activate(slave); 162 163 /* make sure rx/tx buffers are full so clients can assume */ 164 if (!tx) { 165 debug("sandbox_spi: xfer: auto-allocating tx scratch buffer\n"); 166 tx = malloc(bytes); 167 if (!tx) { 168 debug("sandbox_spi: Out of memory\n"); 169 return -ENOMEM; 170 } 171 } 172 if (!rx) { 173 debug("sandbox_spi: xfer: auto-allocating rx scratch buffer\n"); 174 rx = malloc(bytes); 175 if (!rx) { 176 debug("sandbox_spi: Out of memory\n"); 177 return -ENOMEM; 178 } 179 } 180 181 debug("sandbox_spi: xfer: bytes = %u\n tx:", bytes); 182 for (i = 0; i < bytes; ++i) 183 debug(" %u:%02x", i, tx[i]); 184 debug("\n"); 185 186 ret = sss->ops->xfer(sss->priv, tx, rx, bytes); 187 188 debug("sandbox_spi: xfer: got back %i (that's %s)\n rx:", 189 ret, ret ? "bad" : "good"); 190 for (i = 0; i < bytes; ++i) 191 debug(" %u:%02x", i, rx[i]); 192 debug("\n"); 193 194 if (tx != dout) 195 free(tx); 196 if (rx != din) 197 free(rx); 198 199 done: 200 if (flags & SPI_XFER_END) 201 spi_cs_deactivate(slave); 202 203 return ret; 204 } 205 206 /** 207 * Set up a new SPI slave for an fdt node 208 * 209 * @param blob Device tree blob 210 * @param node SPI peripheral node to use 211 * @return 0 if ok, -1 on error 212 */ 213 struct spi_slave *spi_setup_slave_fdt(const void *blob, int slave_node, 214 int spi_node) 215 { 216 return NULL; 217 } 218