From patchwork Tue Apr 2 10:01:50 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hung-ying Tyan X-Patchwork-Id: 232935 X-Patchwork-Delegate: trini@ti.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 DEB0D2C0137 for ; Tue, 2 Apr 2013 21:08:45 +1100 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 97DCD4A23E; Tue, 2 Apr 2013 12:08:44 +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 VUBnQnjUXibs; Tue, 2 Apr 2013 12:08:44 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 2B4394A20A; Tue, 2 Apr 2013 12:08:43 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id B39D44A209 for ; Tue, 2 Apr 2013 12:08:41 +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 38zFPgpsoQ5J for ; Tue, 2 Apr 2013 12:08:40 +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-oa0-f73.google.com (mail-oa0-f73.google.com [209.85.219.73]) by theia.denx.de (Postfix) with ESMTPS id 633B24A204 for ; Tue, 2 Apr 2013 12:08:39 +0200 (CEST) Received: by mail-oa0-f73.google.com with SMTP id o6so45663oag.0 for ; Tue, 02 Apr 2013 03:08:38 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-received:from:to:cc:subject:date:message-id:x-mailer:in-reply-to :references:x-gm-message-state; bh=1lxakVDte/JZzvmnXxYqMzUDY1rT79kD+BtLEKw36cc=; b=GbOtxaJZrA+nA9JKX+/7YDFeIk/927PEaEVD9neNNZ93T6KrjEJuA+2/pJF/NN22W5 PV4eHyh9+jxbFX465a8XgtUC2CtA0rLkuGbDQputr01SJpELc3z5+PahiwUyKsz0ZHKo CyXyp9AyBB16OCmPYp1kL8hkd51ut1VmreMGFl3+oVn5uygZsAVH0crwcsECdHJHMpmY +6tS6UzighaxiRsOmwkSBHCiZukTSIpdwcMMstqkq3OmNfzCCj6EgdHkmJV2ht3aPeln vFZzo9E3e1fTZAvBY+onb/WekEqoyomn+poJUnX99pLmID/CFOGDveKHOPbcFegk3UHz 9RjA== X-Received: by 10.43.136.5 with SMTP id ii5mr11790110icc.11.1364896973133; Tue, 02 Apr 2013 03:02:53 -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 l10si38213ige.0.2013.04.02.03.02.52 (version=TLSv1.1 cipher=AES128-SHA bits=128/128); Tue, 02 Apr 2013 03:02:53 -0700 (PDT) Received: from tyanh-z620.tpe.corp.google.com (tyanh-z620.tpe.corp.google.com [172.30.210.193]) by corp2gmr1-1.hot.corp.google.com (Postfix) with ESMTP id 29D1731C15E; Tue, 2 Apr 2013 03:02:52 -0700 (PDT) Received: by tyanh-z620.tpe.corp.google.com (Postfix, from userid 30259) id 57C6DE0ED4; Tue, 2 Apr 2013 18:02:51 +0800 (CST) From: Hung-ying Tyan To: U-Boot Mailing List Date: Tue, 2 Apr 2013 18:01:50 +0800 Message-Id: <1364896914-17868-4-git-send-email-tyanh@chromium.org> X-Mailer: git-send-email 1.8.1.3 In-Reply-To: <1364896914-17868-1-git-send-email-tyanh@chromium.org> References: <1364896914-17868-1-git-send-email-tyanh@chromium.org> X-Gm-Message-State: ALoCoQmbzCkjBJbVBDOBJzospEyoV+yLnklKOz6ayXCDjX4CIfc5GCv4q8cWm5XmhRJEPimZXzaUlOdodZN09+tFBXovEpC3KzFJ2UOCRwe5J8i6B2bJu9GCZ9Pc8WWOKiNJyqJAKhWp9Ymn6gpFcQcWS2L6IvM8WkW1C8uDVLbtZC41JPARtfhIE84EFcgHIHQyHm4GvIy8 Cc: Tom Rini , u-boot-review@google.com, Randall Spangler Subject: [U-Boot] [PATCH v4 3/7] cros: add SPI support for cros_ec 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 This patch adds SPI support for carrying out the cros_ec protocol. Signed-off-by: Hung-ying Tyan Signed-off-by: Randall Spangler Signed-off-by: Simon Glass Acked-by: Simon Glass --- Changes in v4: - Removed old code and comment. Changes in v3: None Changes in v2: - Fixed warnings of exceeding 80 chars in a line. - Added commit message. - Dropped the period from commit subject. drivers/misc/Makefile | 1 + drivers/misc/cros_ec_spi.c | 161 +++++++++++++++++++++++++++++++++++++++++++++ drivers/spi/exynos_spi.c | 22 +++++++ include/spi.h | 16 +++++ 4 files changed, 200 insertions(+) create mode 100644 drivers/misc/cros_ec_spi.c diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 9363ef9..18209ec 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -32,6 +32,7 @@ COBJS-$(CONFIG_GPIO_LED) += gpio_led.o COBJS-$(CONFIG_FSL_MC9SDZ60) += mc9sdz60.o COBJS-$(CONFIG_CROS_EC) += cros_ec.o COBJS-$(CONFIG_CROS_EC_I2C) += cros_ec_i2c.o +COBJS-$(CONFIG_CROS_EC_SPI) += cros_ec_spi.o COBJS-$(CONFIG_NS87308) += ns87308.o COBJS-$(CONFIG_PDSP188x) += pdsp188x.o COBJS-$(CONFIG_STATUS_LED) += status_led.o diff --git a/drivers/misc/cros_ec_spi.c b/drivers/misc/cros_ec_spi.c new file mode 100644 index 0000000..e15c833 --- /dev/null +++ b/drivers/misc/cros_ec_spi.c @@ -0,0 +1,161 @@ +/* + * Chromium OS cros_ec driver - SPI interface + * + * Copyright (c) 2012 The Chromium OS Authors. + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * The Matrix Keyboard Protocol driver handles talking to the keyboard + * controller chip. Mostly this is for keyboard functions, but some other + * things have slipped in, so we provide generic services to talk to the + * KBC. + */ + +#include +#include +#include + +/** + * Send a command to a LPC CROS_EC device and return the reply. + * + * The device's internal input/output buffers are used. + * + * @param dev CROS_EC device + * @param cmd Command to send (EC_CMD_...) + * @param cmd_version Version of command to send (EC_VER_...) + * @param dout Output data (may be NULL If dout_len=0) + * @param dout_len Size of output data in bytes + * @param dinp Returns pointer to response data. This will be + * untouched unless we return a value > 0. + * @param din_len Maximum size of response in bytes + * @return number of bytes in response, or -1 on error + */ +int cros_ec_spi_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version, + const uint8_t *dout, int dout_len, + uint8_t **dinp, int din_len) +{ + int in_bytes = din_len + 4; /* status, length, checksum, trailer */ + uint8_t *out; + uint8_t *p; + int csum, len; + int rv; + + /* + * Sanity-check input size to make sure it plus transaction overhead + * fits in the internal device buffer. + */ + if (in_bytes > sizeof(dev->din)) { + debug("%s: Cannot receive %d bytes\n", __func__, din_len); + return -1; + } + + /* We represent message length as a byte */ + if (dout_len > 0xff) { + debug("%s: Cannot send %d bytes\n", __func__, dout_len); + return -1; + } + + /* + * Clear input buffer so we don't get false hits for MSG_HEADER + */ + memset(dev->din, '\0', in_bytes); + + if (spi_claim_bus(dev->spi)) { + debug("%s: Cannot claim SPI bus\n", __func__); + return -1; + } + + out = dev->dout; + out[0] = cmd_version; + out[1] = cmd; + out[2] = (uint8_t)dout_len; + memcpy(out + 3, dout, dout_len); + csum = cros_ec_calc_checksum(out, 3) + + cros_ec_calc_checksum(dout, dout_len); + out[3 + dout_len] = (uint8_t)csum; + + /* + * Send output data and receive input data starting such that the + * message body will be dword aligned. + */ + p = dev->din + sizeof(int64_t) - 2; + len = dout_len + 4; + cros_ec_dump_data("out", cmd, out, len); + rv = spi_xfer(dev->spi, max(len, in_bytes) * 8, out, p, + SPI_XFER_BEGIN | SPI_XFER_END); + + spi_release_bus(dev->spi); + + if (rv) { + debug("%s: Cannot complete SPI transfer\n", __func__); + return -1; + } + + len = min(p[1], din_len); + cros_ec_dump_data("in", -1, p, len + 3); + + /* Response code is first byte of message */ + if (p[0] != EC_RES_SUCCESS) { + printf("%s: Returned status %d\n", __func__, p[0]); + return -(int)(p[0]); + } + + /* Check checksum */ + csum = cros_ec_calc_checksum(p, len + 2); + if (csum != p[len + 2]) { + debug("%s: Invalid checksum rx %#02x, calced %#02x\n", __func__, + p[2 + len], csum); + return -1; + } + + /* Anything else is the response data */ + *dinp = p + 2; + + return len; +} + +int cros_ec_spi_decode_fdt(struct cros_ec_dev *dev, const void *blob) +{ + /* Decode interface-specific FDT params */ + dev->max_frequency = fdtdec_get_int(blob, dev->node, + "spi-max-frequency", 500000); + dev->cs = fdtdec_get_int(blob, dev->node, "reg", 0); + + return 0; +} + +/** + * Initialize SPI protocol. + * + * @param dev CROS_EC device + * @param blob Device tree blob + * @return 0 if ok, -1 on error + */ +int cros_ec_spi_init(struct cros_ec_dev *dev, const void *blob) +{ + dev->spi = spi_setup_slave_fdt(blob, dev->parent_node, + dev->cs, dev->max_frequency, 0); + if (!dev->spi) { + debug("%s: Could not setup SPI slave\n", __func__); + return -1; + } + + return 0; +} diff --git a/drivers/spi/exynos_spi.c b/drivers/spi/exynos_spi.c index be60ada..23c5a00 100644 --- a/drivers/spi/exynos_spi.c +++ b/drivers/spi/exynos_spi.c @@ -416,6 +416,28 @@ static int process_nodes(const void *blob, int node_list[], int count) return 0; } +/** + * Set up a new SPI slave for an fdt node + * + * @param blob Device tree blob + * @param node SPI peripheral node to use + * @return 0 if ok, -1 on error + */ +struct spi_slave *spi_setup_slave_fdt(const void *blob, int node, + unsigned int cs, unsigned int max_hz, unsigned int mode) +{ + struct spi_bus *bus; + unsigned int i; + + for (i = 0, bus = spi_bus; i < bus_count; i++, bus++) { + if (bus->node == node) + return spi_setup_slave(i, cs, max_hz, mode); + } + + debug("%s: Failed to find bus node %d\n", __func__, node); + return NULL; +} + /* Sadly there is no error return from this function */ void spi_init(void) { diff --git a/include/spi.h b/include/spi.h index 60e85db..cfcb140 100644 --- a/include/spi.h +++ b/include/spi.h @@ -198,4 +198,20 @@ static inline int spi_w8r8(struct spi_slave *slave, unsigned char byte) return ret < 0 ? ret : din[1]; } +/** + * Set up a SPI slave for a particular device tree node + * + * This calls spi_setup_slave() with the correct bus number. Call + * spi_free_slave() to free it later. + * + * @param blob Device tree blob + * @param node SPI peripheral node to use + * @param cs Chip select to use + * @param max_hz Maximum SCK rate in Hz (0 for default) + * @param mode Clock polarity, clock phase and other parameters + * @return pointer to new spi_slave structure + */ +struct spi_slave *spi_setup_slave_fdt(const void *blob, int node, + unsigned int cs, unsigned int max_hz, unsigned int mode); + #endif /* _SPI_H_ */