Home | History | Annotate | Download | only in spi
      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 <dm.h>
     13 #include <malloc.h>
     14 #include <spi.h>
     15 #include <spi_flash.h>
     16 #include <os.h>
     17 
     18 #include <linux/errno.h>
     19 #include <asm/spi.h>
     20 #include <asm/state.h>
     21 #include <dm/device-internal.h>
     22 
     23 #ifndef CONFIG_SPI_IDLE_VAL
     24 # define CONFIG_SPI_IDLE_VAL 0xFF
     25 #endif
     26 
     27 const char *sandbox_spi_parse_spec(const char *arg, unsigned long *bus,
     28 				   unsigned long *cs)
     29 {
     30 	char *endp;
     31 
     32 	*bus = simple_strtoul(arg, &endp, 0);
     33 	if (*endp != ':' || *bus >= CONFIG_SANDBOX_SPI_MAX_BUS)
     34 		return NULL;
     35 
     36 	*cs = simple_strtoul(endp + 1, &endp, 0);
     37 	if (*endp != ':' || *cs >= CONFIG_SANDBOX_SPI_MAX_CS)
     38 		return NULL;
     39 
     40 	return endp + 1;
     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 static int sandbox_spi_xfer(struct udevice *slave, unsigned int bitlen,
     51 			    const void *dout, void *din, unsigned long flags)
     52 {
     53 	struct udevice *bus = slave->parent;
     54 	struct sandbox_state *state = state_get_current();
     55 	struct dm_spi_emul_ops *ops;
     56 	struct udevice *emul;
     57 	uint bytes = bitlen / 8, i;
     58 	int ret;
     59 	u8 *tx = (void *)dout, *rx = din;
     60 	uint busnum, cs;
     61 
     62 	if (bitlen == 0)
     63 		return 0;
     64 
     65 	/* we can only do 8 bit transfers */
     66 	if (bitlen % 8) {
     67 		printf("sandbox_spi: xfer: invalid bitlen size %u; needs to be 8bit\n",
     68 		       bitlen);
     69 		return -EINVAL;
     70 	}
     71 
     72 	busnum = bus->seq;
     73 	cs = spi_chip_select(slave);
     74 	if (busnum >= CONFIG_SANDBOX_SPI_MAX_BUS ||
     75 	    cs >= CONFIG_SANDBOX_SPI_MAX_CS) {
     76 		printf("%s: busnum=%u, cs=%u: out of range\n", __func__,
     77 		       busnum, cs);
     78 		return -ENOENT;
     79 	}
     80 	ret = sandbox_spi_get_emul(state, bus, slave, &emul);
     81 	if (ret) {
     82 		printf("%s: busnum=%u, cs=%u: no emulation available (err=%d)\n",
     83 		       __func__, busnum, cs, ret);
     84 		return -ENOENT;
     85 	}
     86 	ret = device_probe(emul);
     87 	if (ret)
     88 		return ret;
     89 
     90 	/* make sure rx/tx buffers are full so clients can assume */
     91 	if (!tx) {
     92 		debug("sandbox_spi: xfer: auto-allocating tx scratch buffer\n");
     93 		tx = malloc(bytes);
     94 		if (!tx) {
     95 			debug("sandbox_spi: Out of memory\n");
     96 			return -ENOMEM;
     97 		}
     98 	}
     99 	if (!rx) {
    100 		debug("sandbox_spi: xfer: auto-allocating rx scratch buffer\n");
    101 		rx = malloc(bytes);
    102 		if (!rx) {
    103 			debug("sandbox_spi: Out of memory\n");
    104 			return -ENOMEM;
    105 		}
    106 	}
    107 
    108 	ops = spi_emul_get_ops(emul);
    109 	ret = ops->xfer(emul, bitlen, dout, din, flags);
    110 
    111 	debug("sandbox_spi: xfer: got back %i (that's %s)\n rx:",
    112 	      ret, ret ? "bad" : "good");
    113 	for (i = 0; i < bytes; ++i)
    114 		debug(" %u:%02x", i, rx[i]);
    115 	debug("\n");
    116 
    117 	if (tx != dout)
    118 		free(tx);
    119 	if (rx != din)
    120 		free(rx);
    121 
    122 	return ret;
    123 }
    124 
    125 static int sandbox_spi_set_speed(struct udevice *bus, uint speed)
    126 {
    127 	return 0;
    128 }
    129 
    130 static int sandbox_spi_set_mode(struct udevice *bus, uint 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 */
    139 	if (cs >= 1)
    140 		return -ENODEV;
    141 
    142 	return 0;
    143 }
    144 
    145 static const struct dm_spi_ops sandbox_spi_ops = {
    146 	.xfer		= sandbox_spi_xfer,
    147 	.set_speed	= sandbox_spi_set_speed,
    148 	.set_mode	= sandbox_spi_set_mode,
    149 	.cs_info	= sandbox_cs_info,
    150 };
    151 
    152 static const struct udevice_id sandbox_spi_ids[] = {
    153 	{ .compatible = "sandbox,spi" },
    154 	{ }
    155 };
    156 
    157 U_BOOT_DRIVER(spi_sandbox) = {
    158 	.name	= "spi_sandbox",
    159 	.id	= UCLASS_SPI,
    160 	.of_match = sandbox_spi_ids,
    161 	.ops	= &sandbox_spi_ops,
    162 };
    163