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 <common.h> 14 #include <dm.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/device-internal.h> 24 25 #ifndef CONFIG_SPI_IDLE_VAL 26 # define CONFIG_SPI_IDLE_VAL 0xFF 27 #endif 28 29 const char *sandbox_spi_parse_spec(const char *arg, unsigned long *bus, 30 unsigned long *cs) 31 { 32 char *endp; 33 34 *bus = simple_strtoul(arg, &endp, 0); 35 if (*endp != ':' || *bus >= CONFIG_SANDBOX_SPI_MAX_BUS) 36 return NULL; 37 38 *cs = simple_strtoul(endp + 1, &endp, 0); 39 if (*endp != ':' || *cs >= CONFIG_SANDBOX_SPI_MAX_CS) 40 return NULL; 41 42 return endp + 1; 43 } 44 45 __weak int sandbox_spi_get_emul(struct sandbox_state *state, 46 struct udevice *bus, struct udevice *slave, 47 struct udevice **emulp) 48 { 49 return -ENOENT; 50 } 51 52 static int sandbox_spi_xfer(struct udevice *slave, unsigned int bitlen, 53 const void *dout, void *din, unsigned long flags) 54 { 55 struct udevice *bus = slave->parent; 56 struct sandbox_state *state = state_get_current(); 57 struct dm_spi_emul_ops *ops; 58 struct udevice *emul; 59 uint bytes = bitlen / 8, i; 60 int ret; 61 uint busnum, cs; 62 63 if (bitlen == 0) 64 return 0; 65 66 /* we can only do 8 bit transfers */ 67 if (bitlen % 8) { 68 printf("sandbox_spi: xfer: invalid bitlen size %u; needs to be 8bit\n", 69 bitlen); 70 return -EINVAL; 71 } 72 73 busnum = bus->seq; 74 cs = spi_chip_select(slave); 75 if (busnum >= CONFIG_SANDBOX_SPI_MAX_BUS || 76 cs >= CONFIG_SANDBOX_SPI_MAX_CS) { 77 printf("%s: busnum=%u, cs=%u: out of range\n", __func__, 78 busnum, cs); 79 return -ENOENT; 80 } 81 ret = sandbox_spi_get_emul(state, bus, slave, &emul); 82 if (ret) { 83 printf("%s: busnum=%u, cs=%u: no emulation available (err=%d)\n", 84 __func__, busnum, cs, ret); 85 return -ENOENT; 86 } 87 ret = device_probe(emul); 88 if (ret) 89 return ret; 90 91 ops = spi_emul_get_ops(emul); 92 ret = ops->xfer(emul, bitlen, dout, din, flags); 93 94 log_content("sandbox_spi: xfer: got back %i (that's %s)\n rx:", 95 ret, ret ? "bad" : "good"); 96 if (din) { 97 for (i = 0; i < bytes; ++i) 98 log_content(" %u:%02x", i, ((u8 *)din)[i]); 99 } 100 log_content("\n"); 101 102 return ret; 103 } 104 105 static int sandbox_spi_set_speed(struct udevice *bus, uint speed) 106 { 107 return 0; 108 } 109 110 static int sandbox_spi_set_mode(struct udevice *bus, uint mode) 111 { 112 return 0; 113 } 114 115 static int sandbox_cs_info(struct udevice *bus, uint cs, 116 struct spi_cs_info *info) 117 { 118 /* Always allow activity on CS 0 */ 119 if (cs >= 1) 120 return -ENODEV; 121 122 return 0; 123 } 124 125 static const struct dm_spi_ops sandbox_spi_ops = { 126 .xfer = sandbox_spi_xfer, 127 .set_speed = sandbox_spi_set_speed, 128 .set_mode = sandbox_spi_set_mode, 129 .cs_info = sandbox_cs_info, 130 }; 131 132 static const struct udevice_id sandbox_spi_ids[] = { 133 { .compatible = "sandbox,spi" }, 134 { } 135 }; 136 137 U_BOOT_DRIVER(spi_sandbox) = { 138 .name = "spi_sandbox", 139 .id = UCLASS_SPI, 140 .of_match = sandbox_spi_ids, 141 .ops = &sandbox_spi_ops, 142 }; 143