From patchwork Mon Jun 24 22:36:27 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 253985 X-Patchwork-Delegate: jagannadh.teki@gmail.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id AD7B52C0096 for ; Tue, 25 Jun 2013 08:38:10 +1000 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 611994A02D; Tue, 25 Jun 2013 00:38:05 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id r2yFS-CLNDfQ; Tue, 25 Jun 2013 00:38:05 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id C5C8B4A052; Tue, 25 Jun 2013 00:37:42 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 168B64A027 for ; Tue, 25 Jun 2013 00:37:30 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id q6SDtWr+3BZn for ; Tue, 25 Jun 2013 00:37:23 +0200 (CEST) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from mail-yh0-f74.google.com (mail-yh0-f74.google.com [209.85.213.74]) by theia.denx.de (Postfix) with ESMTPS id 438884A026 for ; Tue, 25 Jun 2013 00:37:13 +0200 (CEST) Received: by mail-yh0-f74.google.com with SMTP id z20so1320563yhz.1 for ; Mon, 24 Jun 2013 15:37:11 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references :x-gm-message-state; bh=Zd6Y6hrW8CTGQpJV8/66UlRBaT/KccMm1z4oHlSRHC0=; b=mQjWDH5guEAcgshmQoGa1iOCAgepVToh2RZb7dpJhgZRN7c+ydX89+dxfnfD2dae04 UP7JzvyZ8XA42clNSjX4wKHvGB2w6kWpUIVdszHYVmxFFtOprmvUXoKHyhwYvUlcLUuV c2l4UqY/VRq2BdFaxdzQIlFckVEb7MgOrQ1FzpXSZVAimiJ/61xlH+6svHEqKfkboIfG xTVYmqc8O9TFOP2NH5chPwDiJLGNl7brpjYkH8HpdIEwwGcjD5nMR75m6U0RD19YRh7L 48QVlgq0hpHcP9+qY3MoQvqNCAk9hkK3OFilPQsyS9u4Vq0f8Ny/dslEjtjsCfSkdqgS eKEg== X-Received: by 10.236.174.202 with SMTP id x50mr14268576yhl.20.1372113431266; Mon, 24 Jun 2013 15:37:11 -0700 (PDT) Received: from corp2gmr1-1.hot.corp.google.com (corp2gmr1-1.hot.corp.google.com [172.24.189.92]) by gmr-mx.google.com with ESMTPS id x33si10101275yhj.0.2013.06.24.15.37.11 for (version=TLSv1.1 cipher=AES128-SHA bits=128/128); Mon, 24 Jun 2013 15:37:11 -0700 (PDT) Received: from kaka.mtv.corp.google.com (kaka.mtv.corp.google.com [172.22.83.1]) by corp2gmr1-1.hot.corp.google.com (Postfix) with ESMTP id 0F72531C24A; Mon, 24 Jun 2013 15:37:11 -0700 (PDT) Received: by kaka.mtv.corp.google.com (Postfix, from userid 121222) id C310816080D; Mon, 24 Jun 2013 15:37:10 -0700 (PDT) From: Simon Glass To: U-Boot Mailing List Date: Mon, 24 Jun 2013 15:36:27 -0700 Message-Id: <1372113389-9415-5-git-send-email-sjg@chromium.org> X-Mailer: git-send-email 1.8.3 In-Reply-To: <1372113389-9415-1-git-send-email-sjg@chromium.org> References: <1372113389-9415-1-git-send-email-sjg@chromium.org> X-Gm-Message-State: ALoCoQnMSkrHr7dIvVqK6Pnei4JpIy+7n5rCLkq6+hgxXniYcH0LReXmBbQWvXRD8Uv6SpJlvugMFBNovyz0orba5li+WPTB1a4qFIRYNu+uMB4ZL0YJlCfSbOq+uD7qafuj1vhMfZpRfus6aT+mpVLaagkn7EmJadaIGt6w3YRb/YWBFcfyAJs/Rcd/CLpweixglqWzL6bH Cc: u-boot-review@google.com, Jagannadha Sutradharudu Teki Subject: [U-Boot] [PATCH v4 4/6] sandbox: spi: Add SPI emulation bus X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.11 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de From: Mike Frysinger This adds a SPI framework for people to hook up simulated SPI clients. Signed-off-by: Mike Frysinger Signed-off-by: Simon Glass --- Changes in v4: - Add additional error checking - Fix new checkpatch warnings - Rebase on top of recent spi changes - Rename sb to sandbox - Update copyright year Changes in v3: - rearchitected on top of state/getopt support Changes in v2: None arch/sandbox/include/asm/config.h | 8 ++ arch/sandbox/include/asm/spi.h | 58 +++++++++++ arch/sandbox/include/asm/state.h | 9 ++ drivers/spi/Makefile | 1 + drivers/spi/sandbox_spi.c | 199 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 275 insertions(+) create mode 100644 arch/sandbox/include/asm/spi.h create mode 100644 drivers/spi/sandbox_spi.c diff --git a/arch/sandbox/include/asm/config.h b/arch/sandbox/include/asm/config.h index 2ef0564..0899fee 100644 --- a/arch/sandbox/include/asm/config.h +++ b/arch/sandbox/include/asm/config.h @@ -23,4 +23,12 @@ #define CONFIG_SANDBOX_ARCH +/* Used by drivers/spi/sandbox_spi.c and arch/sandbox/include/asm/state.h */ +#ifndef CONFIG_SANDBOX_SPI_MAX_BUS +#define CONFIG_SANDBOX_SPI_MAX_BUS 1 +#endif +#ifndef CONFIG_SANDBOX_SPI_MAX_CS +#define CONFIG_SANDBOX_SPI_MAX_CS 10 +#endif + #endif diff --git a/arch/sandbox/include/asm/spi.h b/arch/sandbox/include/asm/spi.h new file mode 100644 index 0000000..49b4a0f --- /dev/null +++ b/arch/sandbox/include/asm/spi.h @@ -0,0 +1,58 @@ +/* + * Simulate a SPI port and clients (see README.sandbox for details) + * + * Copyright (c) 2011-2013 The Chromium OS Authors. + * See file CREDITS for list of people who contributed to this + * project. + * + * Licensed under the GPL-2 or later. + */ + +#ifndef __ASM_SPI_H__ +#define __ASM_SPI_H__ + +#include + +/* + * The interface between the SPI bus and the SPI client. The bus will + * instantiate a client, and that then call into it via these entry + * points. These should be enough for the client to emulate the SPI + * device just like the real hardware. + */ +struct sandbox_spi_emu_ops { + /* The bus wants to instantiate a new client, so setup everything */ + int (*setup)(void **priv, const char *spec); + /* The bus is done with us, so break things down */ + void (*free)(void *priv); + /* The CS has been "activated" -- we won't worry about low/high */ + void (*cs_activate)(void *priv); + /* The CS has been "deactivated" -- we won't worry about low/high */ + void (*cs_deactivate)(void *priv); + /* The client is rx-ing bytes from the bus, so it should tx some */ + int (*xfer)(void *priv, const u8 *rx, u8 *tx, uint bytes); +}; + +/* + * There are times when the data lines are allowed to tristate. What + * is actually sensed on the line depends on the hardware. It could + * always be 0xFF/0x00 (if there are pull ups/downs), or things could + * float and so we'd get garbage back. This func encapsulates that + * scenario so we can worry about the details here. + */ +static inline void sandbox_spi_tristate(u8 *buf, uint len) +{ + /* XXX: make this into a user config option ? */ + memset(buf, 0xff, len); +} + +/* + * Extract the bus/cs from the spi spec and return the start of the spi + * client spec. If the bus/cs are invalid for the current config, then + * it returns NULL. + * + * Example: arg="0:1:foo" will set bus to 0, cs to 1, and return "foo" + */ +const char *sandbox_spi_parse_spec(const char *arg, unsigned long *bus, + unsigned long *cs); + +#endif diff --git a/arch/sandbox/include/asm/state.h b/arch/sandbox/include/asm/state.h index 9552708..0d35554 100644 --- a/arch/sandbox/include/asm/state.h +++ b/arch/sandbox/include/asm/state.h @@ -31,6 +31,11 @@ enum exit_type_id { STATE_EXIT_POWER_OFF, }; +struct sandbox_spi_info { + const char *spec; + const struct sandbox_spi_emu_ops *ops; +}; + /* The complete state of the test system */ struct sandbox_state { const char *cmd; /* Command to execute */ @@ -39,6 +44,10 @@ struct sandbox_state { const char *parse_err; /* Error to report from parsing */ int argc; /* Program arguments */ char **argv; + + /* Pointer to information for each SPI bus/cs */ + struct sandbox_spi_info spi[CONFIG_SANDBOX_SPI_MAX_BUS] + [CONFIG_SANDBOX_SPI_MAX_CS]; }; /** diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index d08609e..56d67db 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -47,6 +47,7 @@ COBJS-$(CONFIG_MXC_SPI) += mxc_spi.o COBJS-$(CONFIG_MXS_SPI) += mxs_spi.o COBJS-$(CONFIG_OC_TINY_SPI) += oc_tiny_spi.o COBJS-$(CONFIG_OMAP3_SPI) += omap3_spi.o +COBJS-$(CONFIG_SANDBOX_SPI) += sandbox_spi.o COBJS-$(CONFIG_SOFT_SPI) += soft_spi.o COBJS-$(CONFIG_SH_SPI) += sh_spi.o COBJS-$(CONFIG_FSL_ESPI) += fsl_espi.o diff --git a/drivers/spi/sandbox_spi.c b/drivers/spi/sandbox_spi.c new file mode 100644 index 0000000..51d5977 --- /dev/null +++ b/drivers/spi/sandbox_spi.c @@ -0,0 +1,199 @@ +/* + * Simulate a SPI port + * + * Copyright (c) 2011-2013 The Chromium OS Authors. + * See file CREDITS for list of people who contributed to this + * project. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include + +#include +#include +#include + +#ifndef CONFIG_SPI_IDLE_VAL +# define CONFIG_SPI_IDLE_VAL 0xFF +#endif + +struct sandbox_spi_slave { + struct spi_slave slave; + const struct sandbox_spi_emu_ops *ops; + void *priv; +}; + +#define to_sandbox_spi_slave(s) container_of(s, struct sandbox_spi_slave, slave) + +const char *sandbox_spi_parse_spec(const char *arg, unsigned long *bus, + unsigned long *cs) +{ + char *endp; + + *bus = simple_strtoul(arg, &endp, 0); + if (*endp != ':' || *bus >= CONFIG_SANDBOX_SPI_MAX_BUS) + return NULL; + + *cs = simple_strtoul(endp + 1, &endp, 0); + if (*endp != ':' || *cs >= CONFIG_SANDBOX_SPI_MAX_CS) + return NULL; + + return endp + 1; +} + +int spi_cs_is_valid(unsigned int bus, unsigned int cs) +{ + return bus < CONFIG_SANDBOX_SPI_MAX_BUS && + cs < CONFIG_SANDBOX_SPI_MAX_CS; +} + +void spi_cs_activate(struct spi_slave *slave) +{ + struct sandbox_spi_slave *sss = to_sandbox_spi_slave(slave); + + debug("sandbox_spi: activating CS\n"); + if (sss->ops->cs_activate) + sss->ops->cs_activate(sss->priv); +} + +void spi_cs_deactivate(struct spi_slave *slave) +{ + struct sandbox_spi_slave *sss = to_sandbox_spi_slave(slave); + + debug("sandbox_spi: deactivating CS\n"); + if (sss->ops->cs_deactivate) + sss->ops->cs_deactivate(sss->priv); +} + +void spi_init(void) +{ +} + +void spi_set_speed(struct spi_slave *slave, uint hz) +{ +} + +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode) +{ + struct sandbox_spi_slave *sss; + struct sandbox_state *state = state_get_current(); + const char *spec; + + if (!spi_cs_is_valid(bus, cs)) { + debug("sandbox_spi: Invalid SPI bus/cs\n"); + return NULL; + } + + sss = spi_alloc_slave(struct sandbox_spi_slave, bus, cs); + if (!sss) { + debug("sandbox_spi: Out of memory\n"); + return NULL; + } + + spec = state->spi[bus][cs].spec; + sss->ops = state->spi[bus][cs].ops; + if (!spec || !sss->ops || sss->ops->setup(&sss->priv, spec)) { + free(sss); + printf("sandbox_spi: unable to locate a slave client\n"); + return NULL; + } + + return &sss->slave; +} + +void spi_free_slave(struct spi_slave *slave) +{ + struct sandbox_spi_slave *sss = to_sandbox_spi_slave(slave); + + debug("sandbox_spi: releasing slave\n"); + + if (sss->ops->free) + sss->ops->free(sss->priv); + + free(sss); +} + +static int spi_bus_claim_cnt[CONFIG_SANDBOX_SPI_MAX_BUS]; + +int spi_claim_bus(struct spi_slave *slave) +{ + if (spi_bus_claim_cnt[slave->bus]++) + printf("sandbox_spi: error: bus already claimed!\n"); + return 0; +} + +void spi_release_bus(struct spi_slave *slave) +{ + if (--spi_bus_claim_cnt[slave->bus]) + printf("sandbox_spi: error: bus freed too often!\n"); +} + +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, + void *din, unsigned long flags) +{ + struct sandbox_spi_slave *sss = to_sandbox_spi_slave(slave); + uint bytes = bitlen / 8, i; + int ret = 0; + u8 *tx = (void *)dout, *rx = din; + + if (bitlen == 0) + goto done; + + /* we can only do 8 bit transfers */ + if (bitlen % 8) { + printf("sandbox_spi: xfer: invalid bitlen size %u; needs to be 8bit\n", + bitlen); + flags |= SPI_XFER_END; + goto done; + } + + if (flags & SPI_XFER_BEGIN) + spi_cs_activate(slave); + + /* make sure rx/tx buffers are full so clients can assume */ + if (!tx) { + debug("sandbox_spi: xfer: auto-allocating tx scratch buffer\n"); + tx = malloc(bytes); + if (!tx) { + debug("sandbox_spi: Out of memory\n"); + return -ENOMEM; + } + } + if (!rx) { + debug("sandbox_spi: xfer: auto-allocating rx scratch buffer\n"); + rx = malloc(bytes); + if (!rx) { + debug("sandbox_spi: Out of memory\n"); + return -ENOMEM; + } + } + + debug("sandbox_spi: xfer: bytes = %u\n tx:", bytes); + for (i = 0; i < bytes; ++i) + debug(" %u:%02x", i, tx[i]); + debug("\n"); + + ret = sss->ops->xfer(sss->priv, tx, rx, bytes); + + debug("sandbox_spi: xfer: got back %i (that's %s)\n rx:", + ret, ret ? "bad" : "good"); + for (i = 0; i < bytes; ++i) + debug(" %u:%02x", i, rx[i]); + debug("\n"); + + if (tx != dout) + free(tx); + if (rx != din) + free(rx); + + done: + if (flags & SPI_XFER_END) + spi_cs_deactivate(slave); + + return ret; +}