All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH v4 0/7] Add cros-ec protocol driver and enable it in smdk5250
@ 2013-04-02 10:01 Hung-ying Tyan
  2013-04-02 10:01 ` [U-Boot] [PATCH v4 1/7] cros: add cros_ec driver Hung-ying Tyan
                   ` (8 more replies)
  0 siblings, 9 replies; 18+ messages in thread
From: Hung-ying Tyan @ 2013-04-02 10:01 UTC (permalink / raw)
  To: u-boot

This patch series adds the drivers for the cros-ec protocol that is used to
communicate with the ChromeOS Embedded Controller (EC). The series also enables
its use in Google Snow based on smdk5250.

The series depends on the following patches:
1) http://patchwork.ozlabs.org/patch/217347 add dts file for Snow
2) mmc series: http://patchwork.ozlabs.org/patch/225008
3) power patches needed by one of the mmc patches
   http://patchwork.ozlabs.org/patch/220060 EXYNOS5: Add function to setup set ps hold
   http://patchwork.ozlabs.org/patch/220061 SMDK5250: Add PMIC voltage settings (needed by one of the mmc patches)
-----

Changes in v4:
- Removed unrelated exynos-spi.txt.
- Moved cros-ec-keyb.txt to the cros-ec-keyb patch.
- Removed old code and comment.

Changes in v3:
- Rearranged #include directives in alphabetical order.
- Removed outdated TODO and irrelevant bug reference in comments.

Changes in v2:
- Moved code from smdk5250.c (non-FDT) to exynos5-dt.c (FDT).
- Moved code from smdk5250.h to exynos5250-dt.h.
- Added gpio node to exynos5250.dtsi.
- Fixed warnings of exceeding 80 chars in a line.
- Added commit message.
- Dropped the period from commit subject.

Hung-ying Tyan (7):
  cros: add cros_ec driver
  cros: add I2C support for cros_ec
  cros: add SPI support for cros_ec
  cros: add LPC support for cros_ec
  cros: adds cros_ec keyboard driver
  cros: exynos: add cros-ec device nodes to exynos5250-snow.dts
  cros: enable cros-ec for smdk5250

 README                                          |    5 +
 arch/arm/dts/exynos5250.dtsi                    |    3 +
 board/samsung/dts/exynos5250-snow.dts           |   82 ++
 board/samsung/smdk5250/exynos5-dt.c             |   45 +
 doc/device-tree-bindings/input/cros-ec-keyb.txt |   79 ++
 doc/device-tree-bindings/misc/cros-ec.txt       |   38 +
 drivers/input/Makefile                          |    1 +
 drivers/input/cros_ec_keyb.c                    |  261 ++++
 drivers/misc/Makefile                           |    4 +
 drivers/misc/cros_ec.c                          | 1304 ++++++++++++++++++++
 drivers/misc/cros_ec_i2c.c                      |  199 ++++
 drivers/misc/cros_ec_lpc.c                      |  283 +++++
 drivers/misc/cros_ec_spi.c                      |  161 +++
 drivers/spi/exynos_spi.c                        |   22 +
 include/configs/exynos5250-dt.h                 |   10 +-
 include/cros_ec.h                               |  449 +++++++
 include/cros_ec_message.h                       |   44 +
 include/ec_commands.h                           | 1440 +++++++++++++++++++++++
 include/fdtdec.h                                |    2 +
 include/spi.h                                   |   16 +
 lib/fdtdec.c                                    |    2 +
 21 files changed, 4449 insertions(+), 1 deletion(-)
 create mode 100644 doc/device-tree-bindings/input/cros-ec-keyb.txt
 create mode 100644 doc/device-tree-bindings/misc/cros-ec.txt
 create mode 100644 drivers/input/cros_ec_keyb.c
 create mode 100644 drivers/misc/cros_ec.c
 create mode 100644 drivers/misc/cros_ec_i2c.c
 create mode 100644 drivers/misc/cros_ec_lpc.c
 create mode 100644 drivers/misc/cros_ec_spi.c
 create mode 100644 include/cros_ec.h
 create mode 100644 include/cros_ec_message.h
 create mode 100644 include/ec_commands.h

-- 
1.8.1.3

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [U-Boot] [PATCH v4 1/7] cros: add cros_ec driver
  2013-04-02 10:01 [U-Boot] [PATCH v4 0/7] Add cros-ec protocol driver and enable it in smdk5250 Hung-ying Tyan
@ 2013-04-02 10:01 ` Hung-ying Tyan
  2013-04-04 20:13   ` Simon Glass
  2013-04-02 10:01 ` [U-Boot] [PATCH v4 2/7] cros: add I2C support for cros_ec Hung-ying Tyan
                   ` (7 subsequent siblings)
  8 siblings, 1 reply; 18+ messages in thread
From: Hung-ying Tyan @ 2013-04-02 10:01 UTC (permalink / raw)
  To: u-boot

This patch adds the cros_ec driver that implements the protocol for
communicating with Google's ChromeOS embedded controller.

Signed-off-by: Bernie Thompson <bhthompson@chromium.org>
Signed-off-by: Bill Richardson <wfrichar@chromium.org>
Signed-off-by: Che-Liang Chiou <clchiou@chromium.org>
Signed-off-by: Doug Anderson <dianders@chromium.org>
Signed-off-by: Gabe Black <gabeblack@chromium.org>
Signed-off-by: Hung-ying Tyan <tyanh@chromium.org>
Signed-off-by: Louis Yung-Chieh Lo <yjlou@chromium.org>
Signed-off-by: Randall Spangler <rspangler@chromium.org>
Signed-off-by: Sean Paul <seanpaul@chromium.org>
Signed-off-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Vincent Palatin <vpalatin@chromium.org>

---
Changes in v4:
- Removed unrelated exynos-spi.txt.
- Moved cros-ec-keyb.txt to the cros-ec-keyb patch.

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.

 doc/device-tree-bindings/misc/cros-ec.txt |   38 +
 drivers/misc/Makefile                     |    1 +
 drivers/misc/cros_ec.c                    | 1304 ++++++++++++++++++++++++++
 include/cros_ec.h                         |  449 +++++++++
 include/cros_ec_message.h                 |   44 +
 include/ec_commands.h                     | 1440 +++++++++++++++++++++++++++++
 include/fdtdec.h                          |    1 +
 lib/fdtdec.c                              |    1 +
 8 files changed, 3278 insertions(+)
 create mode 100644 doc/device-tree-bindings/misc/cros-ec.txt
 create mode 100644 drivers/misc/cros_ec.c
 create mode 100644 include/cros_ec.h
 create mode 100644 include/cros_ec_message.h
 create mode 100644 include/ec_commands.h

diff --git a/doc/device-tree-bindings/misc/cros-ec.txt b/doc/device-tree-bindings/misc/cros-ec.txt
new file mode 100644
index 0000000..07ea7cd
--- /dev/null
+++ b/doc/device-tree-bindings/misc/cros-ec.txt
@@ -0,0 +1,38 @@
+Chrome OS CROS_EC Binding
+======================
+
+The device tree node which describes the operation of the CROS_EC interface
+is as follows:
+
+Required properties :
+- compatible = "google,cros-ec"
+
+Optional properties :
+- spi-max-frequency : Sets the maximum frequency (in Hz) for SPI bus
+   operation
+- i2c-max-frequency : Sets the maximum frequency (in Hz) for I2C bus
+   operation
+- ec-interrupt : Selects the EC interrupt, defined as a GPIO according
+   to the platform
+- optimise-flash-write : Boolean property - if present then flash blocks
+   containing all 0xff will not be written, since we assume that the EC
+   uses that pattern for erased blocks
+
+The CROS_EC node should appear as a subnode of the interrupt that connects it
+to the EC (e.g. i2c, spi, lpc). The reg property (as usual) will indicate
+the unit address on that bus.
+
+
+Example
+=======
+
+	spi at 131b0000 {
+		cros-ec at 0 {
+			reg = <0>;
+			compatible = "google,cros-ec";
+			spi-max-frequency = <5000000>;
+			ec-interrupt = <&gpio 174 1>;
+			optimise-flash-write;
+			status = "disabled";
+		};
+	};
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 8cdc3b6..33fe822 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -30,6 +30,7 @@ COBJS-$(CONFIG_DS4510)  += ds4510.o
 COBJS-$(CONFIG_CBMEM_CONSOLE) += cbmem_console.o
 COBJS-$(CONFIG_GPIO_LED) += gpio_led.o
 COBJS-$(CONFIG_FSL_MC9SDZ60) += mc9sdz60.o
+COBJS-$(CONFIG_CROS_EC) += cros_ec.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.c b/drivers/misc/cros_ec.c
new file mode 100644
index 0000000..6e774d9
--- /dev/null
+++ b/drivers/misc/cros_ec.c
@@ -0,0 +1,1304 @@
+/*
+ * Chromium OS cros_ec driver
+ *
+ * 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 <common.h>
+#include <command.h>
+#include <i2c.h>
+#include <cros_ec.h>
+#include <fdtdec.h>
+#include <malloc.h>
+#include <spi.h>
+#include <asm/io.h>
+#include <asm-generic/gpio.h>
+
+#ifdef DEBUG_TRACE
+#define debug_trace(fmt, b...)	debug(fmt, #b)
+#else
+#define debug_trace(fmt, b...)
+#endif
+
+enum {
+	/* Timeout waiting for a flash erase command to complete */
+	CROS_EC_CMD_TIMEOUT_MS	= 5000,
+	/* Timeout waiting for a synchronous hash to be recomputed */
+	CROS_EC_CMD_HASH_TIMEOUT_MS = 2000,
+};
+
+static struct cros_ec_dev static_dev, *last_dev;
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Note: depends on enum ec_current_image */
+static const char * const ec_current_image_name[] = {"unknown", "RO", "RW"};
+
+void cros_ec_dump_data(const char *name, int cmd, const uint8_t *data, int len)
+{
+#ifdef DEBUG
+	int i;
+
+	printf("%s: ", name);
+	if (cmd != -1)
+		printf("cmd=%#x: ", cmd);
+	for (i = 0; i < len; i++)
+		printf("%02x ", data[i]);
+	printf("\n");
+#endif
+}
+
+/*
+ * Calculate a simple 8-bit checksum of a data block
+ *
+ * @param data	Data block to checksum
+ * @param size	Size of data block in bytes
+ * @return checksum value (0 to 255)
+ */
+int cros_ec_calc_checksum(const uint8_t *data, int size)
+{
+	int csum, i;
+
+	for (i = csum = 0; i < size; i++)
+		csum += data[i];
+	return csum & 0xff;
+}
+
+static int send_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
+			const void *dout, int dout_len,
+			uint8_t **dinp, int din_len)
+{
+	int ret;
+
+	switch (dev->interface) {
+#ifdef CONFIG_CROS_EC_SPI
+	case CROS_EC_IF_SPI:
+		ret = cros_ec_spi_command(dev, cmd, cmd_version,
+					(const uint8_t *)dout, dout_len,
+					dinp, din_len);
+		break;
+#endif
+#ifdef CONFIG_CROS_EC_I2C
+	case CROS_EC_IF_I2C:
+		ret = cros_ec_i2c_command(dev, cmd, cmd_version,
+					(const uint8_t *)dout, dout_len,
+					dinp, din_len);
+		break;
+#endif
+#ifdef CONFIG_CROS_EC_LPC
+	case CROS_EC_IF_LPC:
+		ret = cros_ec_lpc_command(dev, cmd, cmd_version,
+					(const uint8_t *)dout, dout_len,
+					dinp, din_len);
+		break;
+#endif
+	case CROS_EC_IF_NONE:
+	default:
+		ret = -1;
+	}
+
+	return ret;
+}
+
+/**
+ * Send a command to the 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          Response data (may be NULL If din_len=0).
+ *			If not NULL, it will be updated to point to the data
+ *			and will always be double word aligned (64-bits)
+ * @param din_len       Maximum size of response in bytes
+ * @return number of bytes in response, or -1 on error
+ */
+static int ec_command_inptr(struct cros_ec_dev *dev, uint8_t cmd,
+		int cmd_version, const void *dout, int dout_len, uint8_t **dinp,
+		int din_len)
+{
+	uint8_t *din;
+	int len;
+
+	if (cmd_version != 0 && !dev->cmd_version_is_supported) {
+		debug("%s: Command version >0 unsupported\n", __func__);
+		return -1;
+	}
+	len = send_command(dev, cmd, cmd_version, dout, dout_len,
+				&din, din_len);
+
+	/* If the command doesn't complete, wait a while */
+	if (len == -EC_RES_IN_PROGRESS) {
+		struct ec_response_get_comms_status *resp;
+		ulong start;
+
+		/* Wait for command to complete */
+		start = get_timer(0);
+		do {
+			int ret;
+
+			mdelay(50);	/* Insert some reasonable delay */
+			ret = send_command(dev, EC_CMD_GET_COMMS_STATUS, 0,
+					NULL, 0,
+					(uint8_t **)&resp, sizeof(*resp));
+			if (ret < 0)
+				return ret;
+
+			if (get_timer(start) > CROS_EC_CMD_TIMEOUT_MS) {
+				debug("%s: Command %#02x timeout\n",
+				      __func__, cmd);
+				return -EC_RES_TIMEOUT;
+			}
+		} while (resp->flags & EC_COMMS_STATUS_PROCESSING);
+
+		/* OK it completed, so read the status response */
+		/* not sure why it was 0 for the last argument */
+		len = send_command(dev, EC_CMD_RESEND_RESPONSE, 0,
+				NULL, 0, &din, din_len);
+	}
+
+	debug("%s: len=%d, dinp=%p, *dinp=%p\n", __func__, len, dinp, *dinp);
+	if (dinp) {
+		/* If we have any data to return, it must be 64bit-aligned */
+		assert(len <= 0 || !((uintptr_t)din & 7));
+		*dinp = din;
+	}
+
+	return len;
+}
+
+/**
+ * Send a command to the 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 din           Response data (may be NULL If din_len=0).
+ *			It not NULL, it is a place for ec_command() to copy the
+ *      data to.
+ * @param din_len       Maximum size of response in bytes
+ * @return number of bytes in response, or -1 on error
+ */
+static int ec_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
+		      const void *dout, int dout_len,
+		      void *din, int din_len)
+{
+	uint8_t *in_buffer;
+	int len;
+
+	assert((din_len == 0) || din);
+	len = ec_command_inptr(dev, cmd, cmd_version, dout, dout_len,
+			&in_buffer, din_len);
+	if (len > 0) {
+		/*
+		 * If we were asked to put it somewhere, do so, otherwise just
+		 * disregard the result.
+		 */
+		if (din && in_buffer) {
+			assert(len <= din_len);
+			memmove(din, in_buffer, len);
+		}
+	}
+	return len;
+}
+
+int cros_ec_scan_keyboard(struct cros_ec_dev *dev, struct mbkp_keyscan *scan)
+{
+	if (ec_command(dev, EC_CMD_CROS_EC_STATE, 0, NULL, 0, scan,
+		       sizeof(scan->data)) < sizeof(scan->data))
+		return -1;
+
+	return 0;
+}
+
+int cros_ec_read_id(struct cros_ec_dev *dev, char *id, int maxlen)
+{
+	struct ec_response_get_version *r;
+
+	if (ec_command_inptr(dev, EC_CMD_GET_VERSION, 0, NULL, 0,
+			(uint8_t **)&r, sizeof(*r)) < sizeof(*r))
+		return -1;
+
+	if (maxlen > sizeof(r->version_string_ro))
+		maxlen = sizeof(r->version_string_ro);
+
+	switch (r->current_image) {
+	case EC_IMAGE_RO:
+		memcpy(id, r->version_string_ro, maxlen);
+		break;
+	case EC_IMAGE_RW:
+		memcpy(id, r->version_string_rw, maxlen);
+		break;
+	default:
+		return -1;
+	}
+
+	id[maxlen - 1] = '\0';
+	return 0;
+}
+
+int cros_ec_read_version(struct cros_ec_dev *dev,
+		       struct ec_response_get_version **versionp)
+{
+	if (ec_command_inptr(dev, EC_CMD_GET_VERSION, 0, NULL, 0,
+			(uint8_t **)versionp, sizeof(**versionp))
+			< sizeof(**versionp))
+		return -1;
+
+	return 0;
+}
+
+int cros_ec_read_build_info(struct cros_ec_dev *dev, char **strp)
+{
+	if (ec_command_inptr(dev, EC_CMD_GET_BUILD_INFO, 0, NULL, 0,
+			(uint8_t **)strp, EC_HOST_PARAM_SIZE) < 0)
+		return -1;
+
+	return 0;
+}
+
+int cros_ec_read_current_image(struct cros_ec_dev *dev,
+		enum ec_current_image *image)
+{
+	struct ec_response_get_version *r;
+
+	if (ec_command_inptr(dev, EC_CMD_GET_VERSION, 0, NULL, 0,
+			(uint8_t **)&r, sizeof(*r)) < sizeof(*r))
+		return -1;
+
+	*image = r->current_image;
+	return 0;
+}
+
+static int cros_ec_wait_on_hash_done(struct cros_ec_dev *dev,
+				  struct ec_response_vboot_hash *hash)
+{
+	struct ec_params_vboot_hash p;
+	ulong start;
+
+	start = get_timer(0);
+	while (hash->status == EC_VBOOT_HASH_STATUS_BUSY) {
+		mdelay(50);	/* Insert some reasonable delay */
+
+		p.cmd = EC_VBOOT_HASH_GET;
+		if (ec_command(dev, EC_CMD_VBOOT_HASH, 0, &p, sizeof(p),
+		       hash, sizeof(*hash)) < 0)
+			return -1;
+
+		if (get_timer(start) > CROS_EC_CMD_HASH_TIMEOUT_MS) {
+			debug("%s: EC_VBOOT_HASH_GET timeout\n", __func__);
+			return -EC_RES_TIMEOUT;
+		}
+	}
+	return 0;
+}
+
+
+int cros_ec_read_hash(struct cros_ec_dev *dev,
+		struct ec_response_vboot_hash *hash)
+{
+	struct ec_params_vboot_hash p;
+	int rv;
+
+	p.cmd = EC_VBOOT_HASH_GET;
+	if (ec_command(dev, EC_CMD_VBOOT_HASH, 0, &p, sizeof(p),
+		       hash, sizeof(*hash)) < 0)
+		return -1;
+
+	/* If the EC is busy calculating the hash, fidget until it's done. */
+	rv = cros_ec_wait_on_hash_done(dev, hash);
+	if (rv)
+		return rv;
+
+	/* If the hash is valid, we're done. Otherwise, we have to kick it off
+	 * again and wait for it to complete. Note that we explicitly assume
+	 * that hashing zero bytes is always wrong, even though that would
+	 * produce a valid hash value. */
+	if (hash->status == EC_VBOOT_HASH_STATUS_DONE && hash->size)
+		return 0;
+
+	debug("%s: No valid hash (status=%d size=%d). Compute one...\n",
+	      __func__, hash->status, hash->size);
+
+	p.cmd = EC_VBOOT_HASH_RECALC;
+	p.hash_type = EC_VBOOT_HASH_TYPE_SHA256;
+	p.nonce_size = 0;
+	p.offset = EC_VBOOT_HASH_OFFSET_RW;
+
+	if (ec_command(dev, EC_CMD_VBOOT_HASH, 0, &p, sizeof(p),
+		       hash, sizeof(*hash)) < 0)
+		return -1;
+
+	rv = cros_ec_wait_on_hash_done(dev, hash);
+	if (rv)
+		return rv;
+
+	debug("%s: hash done\n", __func__);
+
+	return 0;
+}
+
+static int cros_ec_invalidate_hash(struct cros_ec_dev *dev)
+{
+	struct ec_params_vboot_hash p;
+	struct ec_response_vboot_hash *hash;
+
+	/* We don't have an explict command for the EC to discard its current
+	 * hash value, so we'll just tell it to calculate one that we know is
+	 * wrong (we claim that hashing zero bytes is always invalid).
+	 */
+	p.cmd = EC_VBOOT_HASH_RECALC;
+	p.hash_type = EC_VBOOT_HASH_TYPE_SHA256;
+	p.nonce_size = 0;
+	p.offset = 0;
+	p.size = 0;
+
+	debug("%s:\n", __func__);
+
+	if (ec_command_inptr(dev, EC_CMD_VBOOT_HASH, 0, &p, sizeof(p),
+		       (uint8_t **)&hash, sizeof(*hash)) < 0)
+		return -1;
+
+	/* No need to wait for it to finish */
+	return 0;
+}
+
+int cros_ec_reboot(struct cros_ec_dev *dev, enum ec_reboot_cmd cmd,
+		uint8_t flags)
+{
+	struct ec_params_reboot_ec p;
+
+	p.cmd = cmd;
+	p.flags = flags;
+
+	if (ec_command_inptr(dev, EC_CMD_REBOOT_EC, 0, &p, sizeof(p), NULL, 0)
+			< 0)
+		return -1;
+
+	if (!(flags & EC_REBOOT_FLAG_ON_AP_SHUTDOWN)) {
+		/*
+		 * EC reboot will take place immediately so delay to allow it
+		 * to complete.  Note that some reboot types (EC_REBOOT_COLD)
+		 * will reboot the AP as well, in which case we won't actually
+		 * get to this point.
+		 */
+		/*
+		 * TODO(rspangler@chromium.org): Would be nice if we had a
+		 * better way to determine when the reboot is complete.  Could
+		 * we poll a memory-mapped LPC value?
+		 */
+		udelay(50000);
+	}
+
+	return 0;
+}
+
+int cros_ec_interrupt_pending(struct cros_ec_dev *dev)
+{
+	/* no interrupt support : always poll */
+	if (!fdt_gpio_isvalid(&dev->ec_int))
+		return 1;
+
+	return !gpio_get_value(dev->ec_int.gpio);
+}
+
+int cros_ec_info(struct cros_ec_dev *dev, struct ec_response_cros_ec_info *info)
+{
+	if (ec_command(dev, EC_CMD_CROS_EC_INFO, 0, NULL, 0, info,
+			sizeof(*info)) < sizeof(*info))
+		return -1;
+
+	return 0;
+}
+
+int cros_ec_get_host_events(struct cros_ec_dev *dev, uint32_t *events_ptr)
+{
+	struct ec_response_host_event_mask *resp;
+
+	/*
+	 * Use the B copy of the event flags, because the main copy is already
+	 * used by ACPI/SMI.
+	 */
+	if (ec_command_inptr(dev, EC_CMD_HOST_EVENT_GET_B, 0, NULL, 0,
+		       (uint8_t **)&resp, sizeof(*resp)) < sizeof(*resp))
+		return -1;
+
+	if (resp->mask & EC_HOST_EVENT_MASK(EC_HOST_EVENT_INVALID))
+		return -1;
+
+	*events_ptr = resp->mask;
+	return 0;
+}
+
+int cros_ec_clear_host_events(struct cros_ec_dev *dev, uint32_t events)
+{
+	struct ec_params_host_event_mask params;
+
+	params.mask = events;
+
+	/*
+	 * Use the B copy of the event flags, so it affects the data returned
+	 * by cros_ec_get_host_events().
+	 */
+	if (ec_command_inptr(dev, EC_CMD_HOST_EVENT_CLEAR_B, 0,
+		       &params, sizeof(params), NULL, 0) < 0)
+		return -1;
+
+	return 0;
+}
+
+int cros_ec_flash_protect(struct cros_ec_dev *dev,
+		       uint32_t set_mask, uint32_t set_flags,
+		       struct ec_response_flash_protect *resp)
+{
+	struct ec_params_flash_protect params;
+
+	params.mask = set_mask;
+	params.flags = set_flags;
+
+	if (ec_command(dev, EC_CMD_FLASH_PROTECT, EC_VER_FLASH_PROTECT,
+		       &params, sizeof(params),
+		       resp, sizeof(*resp)) < sizeof(*resp))
+		return -1;
+
+	return 0;
+}
+
+static int cros_ec_check_version(struct cros_ec_dev *dev)
+{
+	struct ec_params_hello req;
+	struct ec_response_hello *resp;
+
+#ifdef CONFIG_CROS_EC_LPC
+	/* LPC has its own way of doing this */
+	if (dev->interface == CROS_EC_IF_LPC)
+		return cros_ec_lpc_check_version(dev);
+#endif
+
+	/*
+	 * TODO(sjg at chromium.org).
+	 * There is a strange oddity here with the EC. We could just ignore
+	 * the response, i.e. pass the last two parameters as NULL and 0.
+	 * In this case we won't read back very many bytes from the EC.
+	 * On the I2C bus the EC gets upset about this and will try to send
+	 * the bytes anyway. This means that we will have to wait for that
+	 * to complete before continuing with a new EC command.
+	 *
+	 * This problem is probably unique to the I2C bus.
+	 *
+	 * So for now, just read all the data anyway.
+	 */
+	dev->cmd_version_is_supported = 1;
+	if (ec_command_inptr(dev, EC_CMD_HELLO, 0, &req, sizeof(req),
+		       (uint8_t **)&resp, sizeof(*resp)) > 0) {
+		/* It appears to understand new version commands */
+		dev->cmd_version_is_supported = 1;
+	} else {
+		dev->cmd_version_is_supported = 0;
+		if (ec_command_inptr(dev, EC_CMD_HELLO, 0, &req,
+			      sizeof(req), (uint8_t **)&resp,
+			      sizeof(*resp)) < 0) {
+			debug("%s: Failed both old and new command style\n",
+				__func__);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+int cros_ec_test(struct cros_ec_dev *dev)
+{
+	struct ec_params_hello req;
+	struct ec_response_hello *resp;
+
+	req.in_data = 0x12345678;
+	if (ec_command_inptr(dev, EC_CMD_HELLO, 0, &req, sizeof(req),
+		       (uint8_t **)&resp, sizeof(*resp)) < sizeof(*resp)) {
+		printf("ec_command_inptr() returned error\n");
+		return -1;
+	}
+	if (resp->out_data != req.in_data + 0x01020304) {
+		printf("Received invalid handshake %x\n", resp->out_data);
+		return -1;
+	}
+
+	return 0;
+}
+
+int cros_ec_flash_offset(struct cros_ec_dev *dev, enum ec_flash_region region,
+		      uint32_t *offset, uint32_t *size)
+{
+	struct ec_params_flash_region_info p;
+	struct ec_response_flash_region_info *r;
+	int ret;
+
+	p.region = region;
+	ret = ec_command_inptr(dev, EC_CMD_FLASH_REGION_INFO,
+			 EC_VER_FLASH_REGION_INFO,
+			 &p, sizeof(p), (uint8_t **)&r, sizeof(*r));
+	if (ret != sizeof(*r))
+		return -1;
+
+	if (offset)
+		*offset = r->offset;
+	if (size)
+		*size = r->size;
+
+	return 0;
+}
+
+int cros_ec_flash_erase(struct cros_ec_dev *dev, uint32_t offset, uint32_t size)
+{
+	struct ec_params_flash_erase p;
+
+	p.offset = offset;
+	p.size = size;
+	return ec_command_inptr(dev, EC_CMD_FLASH_ERASE, 0, &p, sizeof(p),
+			NULL, 0);
+}
+
+/**
+ * Write a single block to the flash
+ *
+ * Write a block of data to the EC flash. The size must not exceed the flash
+ * write block size which you can obtain from cros_ec_flash_write_burst_size().
+ *
+ * The offset starts at 0. You can obtain the region information from
+ * cros_ec_flash_offset() to find out where to write for a particular region.
+ *
+ * Attempting to write to the region where the EC is currently running from
+ * will result in an error.
+ *
+ * @param dev		CROS-EC device
+ * @param data		Pointer to data buffer to write
+ * @param offset	Offset within flash to write to.
+ * @param size		Number of bytes to write
+ * @return 0 if ok, -1 on error
+ */
+static int cros_ec_flash_write_block(struct cros_ec_dev *dev,
+		const uint8_t *data, uint32_t offset, uint32_t size)
+{
+	struct ec_params_flash_write p;
+
+	p.offset = offset;
+	p.size = size;
+	assert(data && p.size <= sizeof(p.data));
+	memcpy(p.data, data, p.size);
+
+	return ec_command_inptr(dev, EC_CMD_FLASH_WRITE, 0,
+			  &p, sizeof(p), NULL, 0) >= 0 ? 0 : -1;
+}
+
+/**
+ * Return optimal flash write burst size
+ */
+static int cros_ec_flash_write_burst_size(struct cros_ec_dev *dev)
+{
+	struct ec_params_flash_write p;
+	return sizeof(p.data);
+}
+
+/**
+ * Check if a block of data is erased (all 0xff)
+ *
+ * This function is useful when dealing with flash, for checking whether a
+ * data block is erased and thus does not need to be programmed.
+ *
+ * @param data		Pointer to data to check (must be word-aligned)
+ * @param size		Number of bytes to check (must be word-aligned)
+ * @return 0 if erased, non-zero if any word is not erased
+ */
+static int cros_ec_data_is_erased(const uint32_t *data, int size)
+{
+	assert(!(size & 3));
+	size /= sizeof(uint32_t);
+	for (; size > 0; size -= 4, data++)
+		if (*data != -1U)
+			return 0;
+
+	return 1;
+}
+
+int cros_ec_flash_write(struct cros_ec_dev *dev, const uint8_t *data,
+		     uint32_t offset, uint32_t size)
+{
+	uint32_t burst = cros_ec_flash_write_burst_size(dev);
+	uint32_t end, off;
+	int ret;
+
+	/*
+	 * TODO: round up to the nearest multiple of write size.  Can get away
+	 * without that on link right now because its write size is 4 bytes.
+	 */
+	end = offset + size;
+	for (off = offset; off < end; off += burst, data += burst) {
+		uint32_t todo;
+
+		/* If the data is empty, there is no point in programming it */
+		todo = min(end - off, burst);
+		if (dev->optimise_flash_write &&
+				cros_ec_data_is_erased((uint32_t *)data, todo))
+			continue;
+
+		ret = cros_ec_flash_write_block(dev, data, off, todo);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+/**
+ * Read a single block from the flash
+ *
+ * Read a block of data from the EC flash. The size must not exceed the flash
+ * write block size which you can obtain from cros_ec_flash_write_burst_size().
+ *
+ * The offset starts at 0. You can obtain the region information from
+ * cros_ec_flash_offset() to find out where to read for a particular region.
+ *
+ * @param dev		CROS-EC device
+ * @param data		Pointer to data buffer to read into
+ * @param offset	Offset within flash to read from
+ * @param size		Number of bytes to read
+ * @return 0 if ok, -1 on error
+ */
+static int cros_ec_flash_read_block(struct cros_ec_dev *dev, uint8_t *data,
+				 uint32_t offset, uint32_t size)
+{
+	struct ec_params_flash_read p;
+
+	p.offset = offset;
+	p.size = size;
+
+	return ec_command(dev, EC_CMD_FLASH_READ, 0,
+			  &p, sizeof(p), data, size) >= 0 ? 0 : -1;
+}
+
+int cros_ec_flash_read(struct cros_ec_dev *dev, uint8_t *data, uint32_t offset,
+		    uint32_t size)
+{
+	uint32_t burst = cros_ec_flash_write_burst_size(dev);
+	uint32_t end, off;
+	int ret;
+
+	end = offset + size;
+	for (off = offset; off < end; off += burst, data += burst) {
+		ret = cros_ec_flash_read_block(dev, data, off,
+					    min(end - off, burst));
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+int cros_ec_flash_update_rw(struct cros_ec_dev *dev,
+			 const uint8_t *image, int image_size)
+{
+	uint32_t rw_offset, rw_size;
+	int ret;
+
+	if (cros_ec_flash_offset(dev, EC_FLASH_REGION_RW, &rw_offset, &rw_size))
+		return -1;
+	if (image_size > rw_size)
+		return -1;
+
+	/* Invalidate the existing hash, just in case the AP reboots
+	 * unexpectedly during the update. If that happened, the EC RW firmware
+	 * would be invalid, but the EC would still have the original hash.
+	 */
+	ret = cros_ec_invalidate_hash(dev);
+	if (ret)
+		return ret;
+
+	/*
+	 * Erase the entire RW section, so that the EC doesn't see any garbage
+	 * past the new image if it's smaller than the current image.
+	 *
+	 * TODO: could optimize this to erase just the current image, since
+	 * presumably everything past that is 0xff's.  But would still need to
+	 * round up to the nearest multiple of erase size.
+	 */
+	ret = cros_ec_flash_erase(dev, rw_offset, rw_size);
+	if (ret)
+		return ret;
+
+	/* Write the image */
+	ret = cros_ec_flash_write(dev, image, rw_offset, image_size);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+int cros_ec_read_vbnvcontext(struct cros_ec_dev *dev, uint8_t *block)
+{
+	struct ec_params_vbnvcontext p;
+	int len;
+
+	p.op = EC_VBNV_CONTEXT_OP_READ;
+
+	len = ec_command(dev, EC_CMD_VBNV_CONTEXT, EC_VER_VBNV_CONTEXT,
+			&p, sizeof(p), block, EC_VBNV_BLOCK_SIZE);
+	if (len < EC_VBNV_BLOCK_SIZE)
+		return -1;
+
+	return 0;
+}
+
+int cros_ec_write_vbnvcontext(struct cros_ec_dev *dev, const uint8_t *block)
+{
+	struct ec_params_vbnvcontext p;
+	int len;
+
+	p.op = EC_VBNV_CONTEXT_OP_WRITE;
+	memcpy(p.block, block, sizeof(p.block));
+
+	len = ec_command_inptr(dev, EC_CMD_VBNV_CONTEXT, EC_VER_VBNV_CONTEXT,
+			&p, sizeof(p), NULL, 0);
+	if (len < 0)
+		return -1;
+
+	return 0;
+}
+
+int cros_ec_set_ldo(struct cros_ec_dev *dev, uint8_t index, uint8_t state)
+{
+	struct ec_params_ldo_set params;
+
+	params.index = index;
+	params.state = state;
+
+	if (ec_command_inptr(dev, EC_CMD_LDO_SET, 0,
+		       &params, sizeof(params),
+		       NULL, 0))
+		return -1;
+
+	return 0;
+}
+
+int cros_ec_get_ldo(struct cros_ec_dev *dev, uint8_t index, uint8_t *state)
+{
+	struct ec_params_ldo_get params;
+	struct ec_response_ldo_get *resp;
+
+	params.index = index;
+
+	if (ec_command_inptr(dev, EC_CMD_LDO_GET, 0,
+		       &params, sizeof(params),
+		       (uint8_t **)&resp, sizeof(*resp)) < sizeof(*resp))
+		return -1;
+
+	*state = resp->state;
+
+	return 0;
+}
+
+/**
+ * Decode MBKP details from the device tree and allocate a suitable device.
+ *
+ * @param blob		Device tree blob
+ * @param node		Node to decode from
+ * @param devp		Returns a pointer to the new allocated device
+ * @return 0 if ok, -1 on error
+ */
+static int cros_ec_decode_fdt(const void *blob, int node,
+		struct cros_ec_dev **devp)
+{
+	enum fdt_compat_id compat;
+	struct cros_ec_dev *dev;
+	int parent;
+
+	/* See what type of parent we are inside (this is expensive) */
+	parent = fdt_parent_offset(blob, node);
+	if (parent < 0) {
+		debug("%s: Cannot find node parent\n", __func__);
+		return -1;
+	}
+
+	dev = &static_dev;
+	dev->node = node;
+	dev->parent_node = parent;
+
+	compat = fdtdec_lookup(blob, parent);
+	switch (compat) {
+#ifdef CONFIG_CROS_EC_SPI
+	case COMPAT_SAMSUNG_EXYNOS_SPI:
+		dev->interface = CROS_EC_IF_SPI;
+		if (cros_ec_spi_decode_fdt(dev, blob))
+			return -1;
+		break;
+#endif
+#ifdef CONFIG_CROS_EC_I2C
+	case COMPAT_SAMSUNG_S3C2440_I2C:
+		dev->interface = CROS_EC_IF_I2C;
+		if (cros_ec_i2c_decode_fdt(dev, blob))
+			return -1;
+		break;
+#endif
+#ifdef CONFIG_CROS_EC_LPC
+	case COMPAT_INTEL_LPC:
+		dev->interface = CROS_EC_IF_LPC;
+		break;
+#endif
+	default:
+		debug("%s: Unknown compat id %d\n", __func__, compat);
+		return -1;
+	}
+
+	fdtdec_decode_gpio(blob, node, "ec-interrupt", &dev->ec_int);
+	dev->optimise_flash_write = fdtdec_get_bool(blob, node,
+						    "optimise-flash-write");
+	*devp = dev;
+
+	return 0;
+}
+
+int cros_ec_init(const void *blob, struct cros_ec_dev **cros_ecp)
+{
+	char id[MSG_BYTES];
+	struct cros_ec_dev *dev;
+	int node = 0;
+
+	*cros_ecp = NULL;
+	do {
+		node = fdtdec_next_compatible(blob, node,
+					      COMPAT_GOOGLE_CROS_EC);
+		if (node < 0) {
+			debug("%s: Node not found\n", __func__);
+			return 0;
+		}
+	} while (!fdtdec_get_is_enabled(blob, node));
+
+	if (cros_ec_decode_fdt(blob, node, &dev)) {
+		debug("%s: Failed to decode device.\n", __func__);
+		return -CROS_EC_ERR_FDT_DECODE;
+	}
+
+	switch (dev->interface) {
+#ifdef CONFIG_CROS_EC_SPI
+	case CROS_EC_IF_SPI:
+		if (cros_ec_spi_init(dev, blob)) {
+			debug("%s: Could not setup SPI interface\n", __func__);
+			return -CROS_EC_ERR_DEV_INIT;
+		}
+		break;
+#endif
+#ifdef CONFIG_CROS_EC_I2C
+	case CROS_EC_IF_I2C:
+		if (cros_ec_i2c_init(dev, blob))
+			return -CROS_EC_ERR_DEV_INIT;
+		break;
+#endif
+#ifdef CONFIG_CROS_EC_LPC
+	case CROS_EC_IF_LPC:
+		if (cros_ec_lpc_init(dev, blob))
+			return -CROS_EC_ERR_DEV_INIT;
+		break;
+#endif
+	case CROS_EC_IF_NONE:
+	default:
+		return 0;
+	}
+
+	/* we will poll the EC interrupt line */
+	fdtdec_setup_gpio(&dev->ec_int);
+	if (fdt_gpio_isvalid(&dev->ec_int))
+		gpio_direction_input(dev->ec_int.gpio);
+
+	if (cros_ec_check_version(dev)) {
+		debug("%s: Could not detect CROS-EC version\n", __func__);
+		return -CROS_EC_ERR_CHECK_VERSION;
+	}
+
+	if (cros_ec_read_id(dev, id, sizeof(id))) {
+		debug("%s: Could not read KBC ID\n", __func__);
+		return -CROS_EC_ERR_READ_ID;
+	}
+
+	/* Remember this device for use by the cros_ec command */
+	last_dev = *cros_ecp = dev;
+	debug("Google Chrome EC CROS-EC driver ready, id '%s'\n", id);
+
+	return 0;
+}
+
+#ifdef CONFIG_CMD_CROS_EC
+int cros_ec_decode_region(int argc, char * const argv[])
+{
+	if (argc > 0) {
+		if (0 == strcmp(*argv, "rw"))
+			return EC_FLASH_REGION_RW;
+		else if (0 == strcmp(*argv, "ro"))
+			return EC_FLASH_REGION_RO;
+
+		debug("%s: Invalid region '%s'\n", __func__, *argv);
+	} else {
+		debug("%s: Missing region parameter\n", __func__);
+	}
+
+	return -1;
+}
+
+/**
+ * Perform a flash read or write command
+ *
+ * @param dev		CROS-EC device to read/write
+ * @param is_write	1 do to a write, 0 to do a read
+ * @param argc		Number of arguments
+ * @param argv		Arguments (2 is region, 3 is address)
+ * @return 0 for ok, 1 for a usage error or -ve for ec command error
+ *	(negative EC_RES_...)
+ */
+static int do_read_write(struct cros_ec_dev *dev, int is_write, int argc,
+			 char * const argv[])
+{
+	uint32_t offset, size = -1U, region_size;
+	unsigned long addr;
+	char *endp;
+	int region;
+	int ret;
+
+	region = cros_ec_decode_region(argc - 2, argv + 2);
+	if (region == -1)
+		return 1;
+	if (argc < 4)
+		return 1;
+	addr = simple_strtoul(argv[3], &endp, 16);
+	if (*argv[3] == 0 || *endp != 0)
+		return 1;
+	if (argc > 4) {
+		size = simple_strtoul(argv[4], &endp, 16);
+		if (*argv[4] == 0 || *endp != 0)
+			return 1;
+	}
+
+	ret = cros_ec_flash_offset(dev, region, &offset, &region_size);
+	if (ret) {
+		debug("%s: Could not read region info\n", __func__);
+		return ret;
+	}
+	if (size == -1U)
+		size = region_size;
+
+	ret = is_write ?
+		cros_ec_flash_write(dev, (uint8_t *)addr, offset, size) :
+		cros_ec_flash_read(dev, (uint8_t *)addr, offset, size);
+	if (ret) {
+		debug("%s: Could not %s region\n", __func__,
+		      is_write ? "write" : "read");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int do_cros_ec(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	struct cros_ec_dev *dev = last_dev;
+	const char *cmd;
+	int ret = 0;
+
+	if (argc < 2)
+		return CMD_RET_USAGE;
+
+	cmd = argv[1];
+	if (0 == strcmp("init", cmd)) {
+		ret = cros_ec_init(gd->fdt_blob, &dev);
+		if (ret) {
+			printf("Could not init cros_ec device (err %d)\n", ret);
+			return 1;
+		}
+		return 0;
+	}
+
+	/* Just use the last allocated device; there should be only one */
+	if (!last_dev) {
+		printf("No CROS-EC device available\n");
+		return 1;
+	}
+	if (0 == strcmp("id", cmd)) {
+		char id[MSG_BYTES];
+
+		if (cros_ec_read_id(dev, id, sizeof(id))) {
+			debug("%s: Could not read KBC ID\n", __func__);
+			return 1;
+		}
+		printf("%s\n", id);
+	} else if (0 == strcmp("info", cmd)) {
+		struct ec_response_cros_ec_info info;
+
+		if (cros_ec_info(dev, &info)) {
+			debug("%s: Could not read KBC info\n", __func__);
+			return 1;
+		}
+		printf("rows     = %u\n", info.rows);
+		printf("cols     = %u\n", info.cols);
+		printf("switches = %#x\n", info.switches);
+	} else if (0 == strcmp("curimage", cmd)) {
+		enum ec_current_image image;
+
+		if (cros_ec_read_current_image(dev, &image)) {
+			debug("%s: Could not read KBC image\n", __func__);
+			return 1;
+		}
+		printf("%d\n", image);
+	} else if (0 == strcmp("hash", cmd)) {
+		struct ec_response_vboot_hash hash;
+		int i;
+
+		if (cros_ec_read_hash(dev, &hash)) {
+			debug("%s: Could not read KBC hash\n", __func__);
+			return 1;
+		}
+
+		if (hash.hash_type == EC_VBOOT_HASH_TYPE_SHA256)
+			printf("type:    SHA-256\n");
+		else
+			printf("type:    %d\n", hash.hash_type);
+
+		printf("offset:  0x%08x\n", hash.offset);
+		printf("size:    0x%08x\n", hash.size);
+
+		printf("digest:  ");
+		for (i = 0; i < hash.digest_size; i++)
+			printf("%02x", hash.hash_digest[i]);
+		printf("\n");
+	} else if (0 == strcmp("reboot", cmd)) {
+		int region;
+		enum ec_reboot_cmd cmd;
+
+		if (argc >= 3 && !strcmp(argv[2], "cold"))
+			cmd = EC_REBOOT_COLD;
+		else {
+			region = cros_ec_decode_region(argc - 2, argv + 2);
+			if (region == EC_FLASH_REGION_RO)
+				cmd = EC_REBOOT_JUMP_RO;
+			else if (region == EC_FLASH_REGION_RW)
+				cmd = EC_REBOOT_JUMP_RW;
+			else
+				return CMD_RET_USAGE;
+		}
+
+		if (cros_ec_reboot(dev, cmd, 0)) {
+			debug("%s: Could not reboot KBC\n", __func__);
+			return 1;
+		}
+	} else if (0 == strcmp("events", cmd)) {
+		uint32_t events;
+
+		if (cros_ec_get_host_events(dev, &events)) {
+			debug("%s: Could not read host events\n", __func__);
+			return 1;
+		}
+		printf("0x%08x\n", events);
+	} else if (0 == strcmp("clrevents", cmd)) {
+		uint32_t events = 0x7fffffff;
+
+		if (argc >= 3)
+			events = simple_strtol(argv[2], NULL, 0);
+
+		if (cros_ec_clear_host_events(dev, events)) {
+			debug("%s: Could not clear host events\n", __func__);
+			return 1;
+		}
+	} else if (0 == strcmp("read", cmd)) {
+		ret = do_read_write(dev, 0, argc, argv);
+		if (ret > 0)
+			return CMD_RET_USAGE;
+	} else if (0 == strcmp("write", cmd)) {
+		ret = do_read_write(dev, 1, argc, argv);
+		if (ret > 0)
+			return CMD_RET_USAGE;
+	} else if (0 == strcmp("erase", cmd)) {
+		int region = cros_ec_decode_region(argc - 2, argv + 2);
+		uint32_t offset, size;
+
+		if (region == -1)
+			return CMD_RET_USAGE;
+		if (cros_ec_flash_offset(dev, region, &offset, &size)) {
+			debug("%s: Could not read region info\n", __func__);
+			ret = -1;
+		} else {
+			ret = cros_ec_flash_erase(dev, offset, size);
+			if (ret) {
+				debug("%s: Could not erase region\n",
+				      __func__);
+			}
+		}
+	} else if (0 == strcmp("regioninfo", cmd)) {
+		int region = cros_ec_decode_region(argc - 2, argv + 2);
+		uint32_t offset, size;
+
+		if (region == -1)
+			return CMD_RET_USAGE;
+		ret = cros_ec_flash_offset(dev, region, &offset, &size);
+		if (ret) {
+			debug("%s: Could not read region info\n", __func__);
+		} else {
+			printf("Region: %s\n", region == EC_FLASH_REGION_RO ?
+					"RO" : "RW");
+			printf("Offset: %x\n", offset);
+			printf("Size:   %x\n", size);
+		}
+	} else if (0 == strcmp("vbnvcontext", cmd)) {
+		uint8_t block[EC_VBNV_BLOCK_SIZE];
+		char buf[3];
+		int i, len;
+		unsigned long result;
+
+		if (argc <= 2) {
+			ret = cros_ec_read_vbnvcontext(dev, block);
+			if (!ret) {
+				printf("vbnv_block: ");
+				for (i = 0; i < EC_VBNV_BLOCK_SIZE; i++)
+					printf("%02x", block[i]);
+				putc('\n');
+			}
+		} else {
+			/*
+			 * TODO(clchiou): Move this to a utility function as
+			 * cmd_spi might want to call it.
+			 */
+			memset(block, 0, EC_VBNV_BLOCK_SIZE);
+			len = strlen(argv[2]);
+			buf[2] = '\0';
+			for (i = 0; i < EC_VBNV_BLOCK_SIZE; i++) {
+				if (i * 2 >= len)
+					break;
+				buf[0] = argv[2][i * 2];
+				if (i * 2 + 1 >= len)
+					buf[1] = '0';
+				else
+					buf[1] = argv[2][i * 2 + 1];
+				strict_strtoul(buf, 16, &result);
+				block[i] = result;
+			}
+			ret = cros_ec_write_vbnvcontext(dev, block);
+		}
+		if (ret) {
+			debug("%s: Could not %s VbNvContext\n", __func__,
+					argc <= 2 ?  "read" : "write");
+		}
+	} else if (0 == strcmp("test", cmd)) {
+		int result = cros_ec_test(dev);
+
+		if (result)
+			printf("Test failed with error %d\n", result);
+		else
+			puts("Test passed\n");
+	} else if (0 == strcmp("version", cmd)) {
+		struct ec_response_get_version *p;
+		char *build_string;
+
+		ret = cros_ec_read_version(dev, &p);
+		if (!ret) {
+			/* Print versions */
+			printf("RO version:    %1.*s\n",
+			       sizeof(p->version_string_ro),
+			       p->version_string_ro);
+			printf("RW version:    %1.*s\n",
+			       sizeof(p->version_string_rw),
+			       p->version_string_rw);
+			printf("Firmware copy: %s\n",
+				(p->current_image <
+					ARRAY_SIZE(ec_current_image_name) ?
+				ec_current_image_name[p->current_image] :
+				"?"));
+			ret = cros_ec_read_build_info(dev, &build_string);
+			if (!ret)
+				printf("Build info:    %s\n", build_string);
+		}
+	} else if (0 == strcmp("ldo", cmd)) {
+		uint8_t index, state;
+		char *endp;
+
+		if (argc < 3)
+			return CMD_RET_USAGE;
+		index = simple_strtoul(argv[2], &endp, 10);
+		if (*argv[2] == 0 || *endp != 0)
+			return CMD_RET_USAGE;
+		if (argc > 3) {
+			state = simple_strtoul(argv[3], &endp, 10);
+			if (*argv[3] == 0 || *endp != 0)
+				return CMD_RET_USAGE;
+			ret = cros_ec_set_ldo(dev, index, state);
+		} else {
+			ret = cros_ec_get_ldo(dev, index, &state);
+			if (!ret) {
+				printf("LDO%d: %s\n", index,
+					state == EC_LDO_STATE_ON ?
+					"on" : "off");
+			}
+		}
+
+		if (ret) {
+			debug("%s: Could not access LDO%d\n", __func__, index);
+			return ret;
+		}
+	} else {
+		return CMD_RET_USAGE;
+	}
+
+	if (ret < 0) {
+		printf("Error: CROS-EC command failed (error %d)\n", ret);
+		ret = 1;
+	}
+
+	return ret;
+}
+
+U_BOOT_CMD(
+	crosec,	5,	1,	do_cros_ec,
+	"CROS-EC utility command",
+	"init                Re-init CROS-EC (done on startup automatically)\n"
+	"crosec id                  Read CROS-EC ID\n"
+	"crosec info                Read CROS-EC info\n"
+	"crosec curimage            Read CROS-EC current image\n"
+	"crosec hash                Read CROS-EC hash\n"
+	"crosec reboot [rw | ro | cold]  Reboot CROS-EC\n"
+	"crosec events              Read CROS-EC host events\n"
+	"crosec clrevents [mask]    Clear CROS-EC host events\n"
+	"crosec regioninfo <ro|rw>  Read image info\n"
+	"crosec erase <ro|rw>       Erase EC image\n"
+	"crosec read <ro|rw> <addr> [<size>]   Read EC image\n"
+	"crosec write <ro|rw> <addr> [<size>]  Write EC image\n"
+	"crosec vbnvcontext [hexstring]        Read [write] VbNvContext from EC\n"
+	"crosec ldo <idx> [<state>] Switch/Read LDO state\n"
+	"crosec test                run tests on cros_ec\n"
+	"crosec version             Read CROS-EC version"
+);
+#endif
diff --git a/include/cros_ec.h b/include/cros_ec.h
new file mode 100644
index 0000000..335d5b4
--- /dev/null
+++ b/include/cros_ec.h
@@ -0,0 +1,449 @@
+/*
+ * Chromium OS cros_ec driver
+ *
+ * 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
+ */
+
+#ifndef _CROS_EC_H
+#define _CROS_EC_H
+
+#include <linux/compiler.h>
+#include <ec_commands.h>
+#include <fdtdec.h>
+#include <cros_ec_message.h>
+
+/* Which interface is the device on? */
+enum cros_ec_interface_t {
+	CROS_EC_IF_NONE,
+	CROS_EC_IF_SPI,
+	CROS_EC_IF_I2C,
+	CROS_EC_IF_LPC,	/* Intel Low Pin Count interface */
+};
+
+/* Our configuration information */
+struct cros_ec_dev {
+	enum cros_ec_interface_t interface;
+	struct spi_slave *spi;		/* Our SPI slave, if using SPI */
+	int node;                       /* Our node */
+	int parent_node;		/* Our parent node (interface) */
+	unsigned int cs;		/* Our chip select */
+	unsigned int addr;		/* Device address (for I2C) */
+	unsigned int bus_num;		/* Bus number (for I2C) */
+	unsigned int max_frequency;	/* Maximum interface frequency */
+	struct fdt_gpio_state ec_int;	/* GPIO used as EC interrupt line */
+	int cmd_version_is_supported;   /* Device supports command versions */
+	int optimise_flash_write;	/* Don't write erased flash blocks */
+
+	/*
+	 * These two buffers will always be dword-aligned and include enough
+	 * space for up to 7 word-alignment bytes also, so we can ensure that
+	 * the body of the message is always dword-aligned (64-bit).
+	 *
+	 * We use this alignment to keep ARM and x86 happy. Probably word
+	 * alignment would be OK, there might be a small performance advantage
+	 * to using dword.
+	 */
+	uint8_t din[ALIGN(MSG_BYTES + sizeof(int64_t), sizeof(int64_t))]
+		__aligned(sizeof(int64_t));
+	uint8_t dout[ALIGN(MSG_BYTES + sizeof(int64_t), sizeof(int64_t))]
+		__aligned(sizeof(int64_t));
+};
+
+/*
+ * Hard-code the number of columns we happen to know we have right now.  It
+ * would be more correct to call cros_ec_info() at startup and determine the
+ * actual number of keyboard cols from there.
+ */
+#define CROS_EC_KEYSCAN_COLS 13
+
+/* Information returned by a key scan */
+struct mbkp_keyscan {
+	uint8_t data[CROS_EC_KEYSCAN_COLS];
+};
+
+/**
+ * Read the ID of the CROS-EC device
+ *
+ * The ID is a string identifying the CROS-EC device.
+ *
+ * @param dev		CROS-EC device
+ * @param id		Place to put the ID
+ * @param maxlen	Maximum length of the ID field
+ * @return 0 if ok, -1 on error
+ */
+int cros_ec_read_id(struct cros_ec_dev *dev, char *id, int maxlen);
+
+/**
+ * Read a keyboard scan from the CROS-EC device
+ *
+ * Send a message requesting a keyboard scan and return the result
+ *
+ * @param dev		CROS-EC device
+ * @param scan		Place to put the scan results
+ * @return 0 if ok, -1 on error
+ */
+int cros_ec_scan_keyboard(struct cros_ec_dev *dev, struct mbkp_keyscan *scan);
+
+/**
+ * Read which image is currently running on the CROS-EC device.
+ *
+ * @param dev		CROS-EC device
+ * @param image		Destination for image identifier
+ * @return 0 if ok, <0 on error
+ */
+int cros_ec_read_current_image(struct cros_ec_dev *dev,
+		enum ec_current_image *image);
+
+/**
+ * Read the hash of the CROS-EC device firmware.
+ *
+ * @param dev		CROS-EC device
+ * @param hash		Destination for hash information
+ * @return 0 if ok, <0 on error
+ */
+int cros_ec_read_hash(struct cros_ec_dev *dev,
+		struct ec_response_vboot_hash *hash);
+
+/**
+ * Send a reboot command to the CROS-EC device.
+ *
+ * Note that some reboot commands (such as EC_REBOOT_COLD) also reboot the AP.
+ *
+ * @param dev		CROS-EC device
+ * @param cmd		Reboot command
+ * @param flags         Flags for reboot command (EC_REBOOT_FLAG_*)
+ * @return 0 if ok, <0 on error
+ */
+int cros_ec_reboot(struct cros_ec_dev *dev, enum ec_reboot_cmd cmd,
+		uint8_t flags);
+
+/**
+ * Check if the CROS-EC device has an interrupt pending.
+ *
+ * Read the status of the external interrupt connected to the CROS-EC device.
+ * If no external interrupt is configured, this always returns 1.
+ *
+ * @param dev		CROS-EC device
+ * @return 0 if no interrupt is pending
+ */
+int cros_ec_interrupt_pending(struct cros_ec_dev *dev);
+
+enum {
+	CROS_EC_OK,
+	CROS_EC_ERR = 1,
+	CROS_EC_ERR_FDT_DECODE,
+	CROS_EC_ERR_CHECK_VERSION,
+	CROS_EC_ERR_READ_ID,
+	CROS_EC_ERR_DEV_INIT,
+};
+
+/**
+ * Set up the Chromium OS matrix keyboard protocol
+ *
+ * @param blob		Device tree blob containing setup information
+ * @param cros_ecp        Returns pointer to the cros_ec device, or NULL if none
+ * @return 0 if we got an cros_ec device and all is well (or no cros_ec is
+ *	expected), -ve if we should have an cros_ec device but failed to find
+ *	one, or init failed (-CROS_EC_ERR_...).
+ */
+int cros_ec_init(const void *blob, struct cros_ec_dev **cros_ecp);
+
+/**
+ * Read information about the keyboard matrix
+ *
+ * @param dev		CROS-EC device
+ * @param info		Place to put the info structure
+ */
+int cros_ec_info(struct cros_ec_dev *dev,
+		struct ec_response_cros_ec_info *info);
+
+/**
+ * Read the host event flags
+ *
+ * @param dev		CROS-EC device
+ * @param events_ptr	Destination for event flags.  Not changed on error.
+ * @return 0 if ok, <0 on error
+ */
+int cros_ec_get_host_events(struct cros_ec_dev *dev, uint32_t *events_ptr);
+
+/**
+ * Clear the specified host event flags
+ *
+ * @param dev		CROS-EC device
+ * @param events	Event flags to clear
+ * @return 0 if ok, <0 on error
+ */
+int cros_ec_clear_host_events(struct cros_ec_dev *dev, uint32_t events);
+
+/**
+ * Get/set flash protection
+ *
+ * @param dev		CROS-EC device
+ * @param set_mask	Mask of flags to set; if 0, just retrieves existing
+ *                      protection state without changing it.
+ * @param set_flags	New flag values; only bits in set_mask are applied;
+ *                      ignored if set_mask=0.
+ * @param prot          Destination for updated protection state from EC.
+ * @return 0 if ok, <0 on error
+ */
+int cros_ec_flash_protect(struct cros_ec_dev *dev,
+		       uint32_t set_mask, uint32_t set_flags,
+		       struct ec_response_flash_protect *resp);
+
+
+/**
+ * Run internal tests on the cros_ec interface.
+ *
+ * @param dev		CROS-EC device
+ * @return 0 if ok, <0 if the test failed
+ */
+int cros_ec_test(struct cros_ec_dev *dev);
+
+/**
+ * Update the EC RW copy.
+ *
+ * @param dev		CROS-EC device
+ * @param image		the content to write
+ * @param imafge_size	content length
+ * @return 0 if ok, <0 if the test failed
+ */
+int cros_ec_flash_update_rw(struct cros_ec_dev *dev,
+			 const uint8_t  *image, int image_size);
+
+/**
+ * Return a pointer to the board's CROS-EC device
+ *
+ * This should be implemented by board files.
+ *
+ * @return pointer to CROS-EC device, or NULL if none is available
+ */
+struct cros_ec_dev *board_get_cros_ec_dev(void);
+
+
+/* Internal interfaces */
+int cros_ec_i2c_init(struct cros_ec_dev *dev, const void *blob);
+int cros_ec_spi_init(struct cros_ec_dev *dev, const void *blob);
+int cros_ec_lpc_init(struct cros_ec_dev *dev, const void *blob);
+
+/**
+ * Read information from the fdt for the i2c cros_ec interface
+ *
+ * @param dev		CROS-EC device
+ * @param blob		Device tree blob
+ * @return 0 if ok, -1 if we failed to read all required information
+ */
+int cros_ec_i2c_decode_fdt(struct cros_ec_dev *dev, const void *blob);
+
+/**
+ * Read information from the fdt for the spi cros_ec interface
+ *
+ * @param dev		CROS-EC device
+ * @param blob		Device tree blob
+ * @return 0 if ok, -1 if we failed to read all required information
+ */
+int cros_ec_spi_decode_fdt(struct cros_ec_dev *dev, const void *blob);
+
+/**
+ * Check whether the LPC interface supports new-style commands.
+ *
+ * LPC has its own way of doing this, which involves checking LPC values
+ * visible to the host. Do this, and update dev->cmd_version_is_supported
+ * accordingly.
+ *
+ * @param dev		CROS-EC device to check
+ */
+int cros_ec_lpc_check_version(struct cros_ec_dev *dev);
+
+/**
+ * Send a command to an I2C CROS-EC device and return the reply.
+ *
+ * This rather complicated function deals with sending both old-style and
+ * new-style commands. The old ones have just a command byte and arguments.
+ * The new ones have version, command, arg-len, [args], chksum so are 3 bytes
+ * longer.
+ *
+ * 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
+ * @param din_len       Maximum size of response in bytes
+ * @return number of bytes in response, or -1 on error
+ */
+int cros_ec_i2c_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);
+
+/**
+ * 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
+ * @param din_len       Maximum size of response in bytes
+ * @return number of bytes in response, or -1 on error
+ */
+int cros_ec_lpc_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 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);
+
+/**
+ * Dump a block of data for a command.
+ *
+ * @param name	Name for data (e.g. 'in', 'out')
+ * @param cmd	Command number associated with data, or -1 for none
+ * @param data	Data block to dump
+ * @param len	Length of data block to dump
+ */
+void cros_ec_dump_data(const char *name, int cmd, const uint8_t *data, int len);
+
+/**
+ * Calculate a simple 8-bit checksum of a data block
+ *
+ * @param data	Data block to checksum
+ * @param size	Size of data block in bytes
+ * @return checksum value (0 to 255)
+ */
+int cros_ec_calc_checksum(const uint8_t *data, int size);
+
+/**
+ * Decode a flash region parameter
+ *
+ * @param argc	Number of params remaining
+ * @param argv	List of remaining parameters
+ * @return flash region (EC_FLASH_REGION_...) or -1 on error
+ */
+int cros_ec_decode_region(int argc, char * const argv[]);
+
+int cros_ec_flash_erase(struct cros_ec_dev *dev, uint32_t offset,
+		uint32_t size);
+
+/**
+ * Read data from the flash
+ *
+ * Read an arbitrary amount of data from the EC flash, by repeatedly reading
+ * small blocks.
+ *
+ * The offset starts at 0. You can obtain the region information from
+ * cros_ec_flash_offset() to find out where to read for a particular region.
+ *
+ * @param dev		CROS-EC device
+ * @param data		Pointer to data buffer to read into
+ * @param offset	Offset within flash to read from
+ * @param size		Number of bytes to read
+ * @return 0 if ok, -1 on error
+ */
+int cros_ec_flash_read(struct cros_ec_dev *dev, uint8_t *data, uint32_t offset,
+		    uint32_t size);
+
+/**
+ * Write data to the flash
+ *
+ * Write an arbitrary amount of data to the EC flash, by repeatedly writing
+ * small blocks.
+ *
+ * The offset starts at 0. You can obtain the region information from
+ * cros_ec_flash_offset() to find out where to write for a particular region.
+ *
+ * Attempting to write to the region where the EC is currently running from
+ * will result in an error.
+ *
+ * @param dev		CROS-EC device
+ * @param data		Pointer to data buffer to write
+ * @param offset	Offset within flash to write to.
+ * @param size		Number of bytes to write
+ * @return 0 if ok, -1 on error
+ */
+int cros_ec_flash_write(struct cros_ec_dev *dev, const uint8_t *data,
+		     uint32_t offset, uint32_t size);
+
+/**
+ * Obtain position and size of a flash region
+ *
+ * @param dev		CROS-EC device
+ * @param region	Flash region to query
+ * @param offset	Returns offset of flash region in EC flash
+ * @param size		Returns size of flash region
+ * @return 0 if ok, -1 on error
+ */
+int cros_ec_flash_offset(struct cros_ec_dev *dev, enum ec_flash_region region,
+		      uint32_t *offset, uint32_t *size);
+
+/**
+ * Read/write VbNvContext from/to a CROS-EC device.
+ *
+ * @param dev		CROS-EC device
+ * @param block		Buffer of VbNvContext to be read/write
+ * @return 0 if ok, -1 on error
+ */
+int cros_ec_read_vbnvcontext(struct cros_ec_dev *dev, uint8_t *block);
+int cros_ec_write_vbnvcontext(struct cros_ec_dev *dev, const uint8_t *block);
+
+/**
+ * Read the version information for the EC images
+ *
+ * @param dev		CROS-EC device
+ * @param versionp	This is set to point to the version information
+ * @return 0 if ok, -1 on error
+ */
+int cros_ec_read_version(struct cros_ec_dev *dev,
+		       struct ec_response_get_version **versionp);
+
+/**
+ * Read the build information for the EC
+ *
+ * @param dev		CROS-EC device
+ * @param versionp	This is set to point to the build string
+ * @return 0 if ok, -1 on error
+ */
+int cros_ec_read_build_info(struct cros_ec_dev *dev, char **strp);
+
+/**
+ * Switch on/off a LDO / FET.
+ *
+ * @param dev		CROS-EC device
+ * @param index		index of the LDO/FET to switch
+ * @param state		new state of the LDO/FET : EC_LDO_STATE_ON|OFF
+ * @return 0 if ok, -1 on error
+ */
+int cros_ec_set_ldo(struct cros_ec_dev *dev, uint8_t index, uint8_t state);
+
+/**
+ * Read back a LDO / FET current state.
+ *
+ * @param dev		CROS-EC device
+ * @param index		index of the LDO/FET to switch
+ * @param state		current state of the LDO/FET : EC_LDO_STATE_ON|OFF
+ * @return 0 if ok, -1 on error
+ */
+int cros_ec_get_ldo(struct cros_ec_dev *dev, uint8_t index, uint8_t *state);
+#endif
diff --git a/include/cros_ec_message.h b/include/cros_ec_message.h
new file mode 100644
index 0000000..a2421c7
--- /dev/null
+++ b/include/cros_ec_message.h
@@ -0,0 +1,44 @@
+/*
+ * Chromium OS Matrix Keyboard Message Protocol definitions
+ *
+ * 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
+ */
+
+#ifndef _CROS_MESSAGE_H
+#define _CROS_MESSAGE_H
+
+/*
+ * Command interface between EC and AP, for LPC, I2C and SPI interfaces.
+ *
+ * This is copied from the Chromium OS Open Source Embedded Controller code.
+ */
+enum {
+	/* The header byte, which follows the preamble */
+	MSG_HEADER	= 0xec,
+
+	MSG_HEADER_BYTES	= 3,
+	MSG_TRAILER_BYTES	= 2,
+	MSG_PROTO_BYTES		= MSG_HEADER_BYTES + MSG_TRAILER_BYTES,
+
+	/* Max length of messages */
+	MSG_BYTES		= EC_HOST_PARAM_SIZE + MSG_PROTO_BYTES,
+};
+
+#endif
diff --git a/include/ec_commands.h b/include/ec_commands.h
new file mode 100644
index 0000000..12811cc
--- /dev/null
+++ b/include/ec_commands.h
@@ -0,0 +1,1440 @@
+/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Host communication command constants for Chrome EC */
+
+#ifndef __CROS_EC_COMMANDS_H
+#define __CROS_EC_COMMANDS_H
+
+/*
+ * Protocol overview
+ *
+ * request:  CMD [ P0 P1 P2 ... Pn S ]
+ * response: ERR [ P0 P1 P2 ... Pn S ]
+ *
+ * where the bytes are defined as follow :
+ *      - CMD is the command code. (defined by EC_CMD_ constants)
+ *      - ERR is the error code. (defined by EC_RES_ constants)
+ *      - Px is the optional payload.
+ *        it is not sent if the error code is not success.
+ *        (defined by ec_params_ and ec_response_ structures)
+ *      - S is the checksum which is the sum of all payload bytes.
+ *
+ * On LPC, CMD and ERR are sent/received at EC_LPC_ADDR_KERNEL|USER_CMD
+ * and the payloads are sent/received at EC_LPC_ADDR_KERNEL|USER_PARAM.
+ * On I2C, all bytes are sent serially in the same message.
+ */
+
+/* Current version of this protocol */
+#define EC_PROTO_VERSION          0x00000002
+
+/* Command version mask */
+#define EC_VER_MASK(version) (1UL << (version))
+
+/* I/O addresses for ACPI commands */
+#define EC_LPC_ADDR_ACPI_DATA  0x62
+#define EC_LPC_ADDR_ACPI_CMD   0x66
+
+/* I/O addresses for host command */
+#define EC_LPC_ADDR_HOST_DATA  0x200
+#define EC_LPC_ADDR_HOST_CMD   0x204
+
+/* I/O addresses for host command args and params */
+#define EC_LPC_ADDR_HOST_ARGS  0x800
+#define EC_LPC_ADDR_HOST_PARAM 0x804
+#define EC_HOST_PARAM_SIZE     0x0fc  /* Size of param area in bytes */
+
+/* I/O addresses for host command params, old interface */
+#define EC_LPC_ADDR_OLD_PARAM  0x880
+#define EC_OLD_PARAM_SIZE      0x080  /* Size of param area in bytes */
+
+/* EC command register bit functions */
+#define EC_LPC_CMDR_DATA	(1 << 0)  /* Data ready for host to read */
+#define EC_LPC_CMDR_PENDING	(1 << 1)  /* Write pending to EC */
+#define EC_LPC_CMDR_BUSY	(1 << 2)  /* EC is busy processing a command */
+#define EC_LPC_CMDR_CMD		(1 << 3)  /* Last host write was a command */
+#define EC_LPC_CMDR_ACPI_BRST	(1 << 4)  /* Burst mode (not used) */
+#define EC_LPC_CMDR_SCI		(1 << 5)  /* SCI event is pending */
+#define EC_LPC_CMDR_SMI		(1 << 6)  /* SMI event is pending */
+
+#define EC_LPC_ADDR_MEMMAP       0x900
+#define EC_MEMMAP_SIZE         255 /* ACPI IO buffer max is 255 bytes */
+#define EC_MEMMAP_TEXT_MAX     8   /* Size of a string in the memory map */
+
+/* The offset address of each type of data in mapped memory. */
+#define EC_MEMMAP_TEMP_SENSOR      0x00 /* Temp sensors */
+#define EC_MEMMAP_FAN              0x10 /* Fan speeds */
+#define EC_MEMMAP_TEMP_SENSOR_B    0x18 /* Temp sensors (second set) */
+#define EC_MEMMAP_ID               0x20 /* 'E' 'C' */
+#define EC_MEMMAP_ID_VERSION       0x22 /* Version of data in 0x20 - 0x2f */
+#define EC_MEMMAP_THERMAL_VERSION  0x23 /* Version of data in 0x00 - 0x1f */
+#define EC_MEMMAP_BATTERY_VERSION  0x24 /* Version of data in 0x40 - 0x7f */
+#define EC_MEMMAP_SWITCHES_VERSION 0x25 /* Version of data in 0x30 - 0x33 */
+#define EC_MEMMAP_EVENTS_VERSION   0x26 /* Version of data in 0x34 - 0x3f */
+#define EC_MEMMAP_HOST_CMD_FLAGS   0x27 /* Host command interface flags */
+#define EC_MEMMAP_SWITCHES         0x30
+#define EC_MEMMAP_HOST_EVENTS      0x34
+#define EC_MEMMAP_BATT_VOLT        0x40 /* Battery Present Voltage */
+#define EC_MEMMAP_BATT_RATE        0x44 /* Battery Present Rate */
+#define EC_MEMMAP_BATT_CAP         0x48 /* Battery Remaining Capacity */
+#define EC_MEMMAP_BATT_FLAG        0x4c /* Battery State, defined below */
+#define EC_MEMMAP_BATT_DCAP        0x50 /* Battery Design Capacity */
+#define EC_MEMMAP_BATT_DVLT        0x54 /* Battery Design Voltage */
+#define EC_MEMMAP_BATT_LFCC        0x58 /* Battery Last Full Charge Capacity */
+#define EC_MEMMAP_BATT_CCNT        0x5c /* Battery Cycle Count */
+#define EC_MEMMAP_BATT_MFGR        0x60 /* Battery Manufacturer String */
+#define EC_MEMMAP_BATT_MODEL       0x68 /* Battery Model Number String */
+#define EC_MEMMAP_BATT_SERIAL      0x70 /* Battery Serial Number String */
+#define EC_MEMMAP_BATT_TYPE        0x78 /* Battery Type String */
+
+/* Number of temp sensors at EC_MEMMAP_TEMP_SENSOR */
+#define EC_TEMP_SENSOR_ENTRIES     16
+/*
+ * Number of temp sensors@EC_MEMMAP_TEMP_SENSOR_B.
+ *
+ * Valid only if EC_MEMMAP_THERMAL_VERSION returns >= 2.
+ */
+#define EC_TEMP_SENSOR_B_ENTRIES      8
+#define EC_TEMP_SENSOR_NOT_PRESENT    0xff
+#define EC_TEMP_SENSOR_ERROR          0xfe
+#define EC_TEMP_SENSOR_NOT_POWERED    0xfd
+#define EC_TEMP_SENSOR_NOT_CALIBRATED 0xfc
+/*
+ * The offset of temperature value stored in mapped memory.  This allows
+ * reporting a temperature range of 200K to 454K = -73C to 181C.
+ */
+#define EC_TEMP_SENSOR_OFFSET      200
+
+#define EC_FAN_SPEED_ENTRIES       4       /* Number of fans at EC_MEMMAP_FAN */
+#define EC_FAN_SPEED_NOT_PRESENT   0xffff  /* Entry not present */
+#define EC_FAN_SPEED_STALLED       0xfffe  /* Fan stalled */
+
+/* Battery bit flags at EC_MEMMAP_BATT_FLAG. */
+#define EC_BATT_FLAG_AC_PRESENT   0x01
+#define EC_BATT_FLAG_BATT_PRESENT 0x02
+#define EC_BATT_FLAG_DISCHARGING  0x04
+#define EC_BATT_FLAG_CHARGING     0x08
+#define EC_BATT_FLAG_LEVEL_CRITICAL 0x10
+
+/* Switch flags at EC_MEMMAP_SWITCHES */
+#define EC_SWITCH_LID_OPEN               0x01
+#define EC_SWITCH_POWER_BUTTON_PRESSED   0x02
+#define EC_SWITCH_WRITE_PROTECT_DISABLED 0x04
+/* Recovery requested via keyboard */
+#define EC_SWITCH_KEYBOARD_RECOVERY      0x08
+/* Recovery requested via dedicated signal (from servo board) */
+#define EC_SWITCH_DEDICATED_RECOVERY     0x10
+/* Was fake developer mode switch; now unused.  Remove in next refactor. */
+#define EC_SWITCH_IGNORE0                0x20
+
+/* Host command interface flags */
+/* Host command interface supports LPC args (LPC interface only) */
+#define EC_HOST_CMD_FLAG_LPC_ARGS_SUPPORTED  0x01
+
+/* Wireless switch flags */
+#define EC_WIRELESS_SWITCH_WLAN      0x01
+#define EC_WIRELESS_SWITCH_BLUETOOTH 0x02
+
+/*
+ * This header file is used in coreboot both in C and ACPI code.  The ACPI code
+ * is pre-processed to handle constants but the ASL compiler is unable to
+ * handle actual C code so keep it separate.
+ */
+#ifndef __ACPI__
+
+/*
+ * Define __packed if someone hasn't beat us to it.  Linux kernel style
+ * checking prefers __packed over __attribute__((packed)).
+ */
+#ifndef __packed
+#define __packed __attribute__((packed))
+#endif
+
+/* LPC command status byte masks */
+/* EC has written a byte in the data register and host hasn't read it yet */
+#define EC_LPC_STATUS_TO_HOST     0x01
+/* Host has written a command/data byte and the EC hasn't read it yet */
+#define EC_LPC_STATUS_FROM_HOST   0x02
+/* EC is processing a command */
+#define EC_LPC_STATUS_PROCESSING  0x04
+/* Last write to EC was a command, not data */
+#define EC_LPC_STATUS_LAST_CMD    0x08
+/* EC is in burst mode.  Unsupported by Chrome EC, so this bit is never set */
+#define EC_LPC_STATUS_BURST_MODE  0x10
+/* SCI event is pending (requesting SCI query) */
+#define EC_LPC_STATUS_SCI_PENDING 0x20
+/* SMI event is pending (requesting SMI query) */
+#define EC_LPC_STATUS_SMI_PENDING 0x40
+/* (reserved) */
+#define EC_LPC_STATUS_RESERVED    0x80
+
+/*
+ * EC is busy.  This covers both the EC processing a command, and the host has
+ * written a new command but the EC hasn't picked it up yet.
+ */
+#define EC_LPC_STATUS_BUSY_MASK \
+	(EC_LPC_STATUS_FROM_HOST | EC_LPC_STATUS_PROCESSING)
+
+/* Host command response codes */
+enum ec_status {
+	EC_RES_SUCCESS = 0,
+	EC_RES_INVALID_COMMAND = 1,
+	EC_RES_ERROR = 2,
+	EC_RES_INVALID_PARAM = 3,
+	EC_RES_ACCESS_DENIED = 4,
+	EC_RES_INVALID_RESPONSE = 5,
+	EC_RES_INVALID_VERSION = 6,
+	EC_RES_INVALID_CHECKSUM = 7,
+	EC_RES_IN_PROGRESS = 8,		/* Accepted, command in progress */
+	EC_RES_UNAVAILABLE = 9,		/* No response available */
+	EC_RES_TIMEOUT = 10,		/* We got a timeout */
+	EC_RES_OVERFLOW = 11,		/* Table / data overflow */
+};
+
+/*
+ * Host event codes.  Note these are 1-based, not 0-based, because ACPI query
+ * EC command uses code 0 to mean "no event pending".  We explicitly specify
+ * each value in the enum listing so they won't change if we delete/insert an
+ * item or rearrange the list (it needs to be stable across platforms, not
+ * just within a single compiled instance).
+ */
+enum host_event_code {
+	EC_HOST_EVENT_LID_CLOSED = 1,
+	EC_HOST_EVENT_LID_OPEN = 2,
+	EC_HOST_EVENT_POWER_BUTTON = 3,
+	EC_HOST_EVENT_AC_CONNECTED = 4,
+	EC_HOST_EVENT_AC_DISCONNECTED = 5,
+	EC_HOST_EVENT_BATTERY_LOW = 6,
+	EC_HOST_EVENT_BATTERY_CRITICAL = 7,
+	EC_HOST_EVENT_BATTERY = 8,
+	EC_HOST_EVENT_THERMAL_THRESHOLD = 9,
+	EC_HOST_EVENT_THERMAL_OVERLOAD = 10,
+	EC_HOST_EVENT_THERMAL = 11,
+	EC_HOST_EVENT_USB_CHARGER = 12,
+	EC_HOST_EVENT_KEY_PRESSED = 13,
+	/*
+	 * EC has finished initializing the host interface.  The host can check
+	 * for this event following sending a EC_CMD_REBOOT_EC command to
+	 * determine when the EC is ready to accept subsequent commands.
+	 */
+	EC_HOST_EVENT_INTERFACE_READY = 14,
+	/* Keyboard recovery combo has been pressed */
+	EC_HOST_EVENT_KEYBOARD_RECOVERY = 15,
+
+	/* Shutdown due to thermal overload */
+	EC_HOST_EVENT_THERMAL_SHUTDOWN = 16,
+	/* Shutdown due to battery level too low */
+	EC_HOST_EVENT_BATTERY_SHUTDOWN = 17,
+
+	/*
+	 * The high bit of the event mask is not used as a host event code.  If
+	 * it reads back as set, then the entire event mask should be
+	 * considered invalid by the host.  This can happen when reading the
+	 * raw event status via EC_MEMMAP_HOST_EVENTS but the LPC interface is
+	 * not initialized on the EC, or improperly configured on the host.
+	 */
+	EC_HOST_EVENT_INVALID = 32
+};
+/* Host event mask */
+#define EC_HOST_EVENT_MASK(event_code) (1UL << ((event_code) - 1))
+
+/* Arguments at EC_LPC_ADDR_HOST_ARGS */
+struct ec_lpc_host_args {
+	uint8_t flags;
+	uint8_t command_version;
+	uint8_t data_size;
+	/*
+	 * Checksum; sum of command + flags + command_version + data_size +
+	 * all params/response data bytes.
+	 */
+	uint8_t checksum;
+} __packed;
+
+/* Flags for ec_lpc_host_args.flags */
+/*
+ * Args are from host.  Data area at EC_LPC_ADDR_HOST_PARAM contains command
+ * params.
+ *
+ * If EC gets a command and this flag is not set, this is an old-style command.
+ * Command version is 0 and params from host are at EC_LPC_ADDR_OLD_PARAM with
+ * unknown length.  EC must respond with an old-style response (that is,
+ * withouth setting EC_HOST_ARGS_FLAG_TO_HOST).
+ */
+#define EC_HOST_ARGS_FLAG_FROM_HOST 0x01
+/*
+ * Args are from EC.  Data area at EC_LPC_ADDR_HOST_PARAM contains response.
+ *
+ * If EC responds to a command and this flag is not set, this is an old-style
+ * response.  Command version is 0 and response data from EC is at
+ * EC_LPC_ADDR_OLD_PARAM with unknown length.
+ */
+#define EC_HOST_ARGS_FLAG_TO_HOST   0x02
+
+/*
+ * Notes on commands:
+ *
+ * Each command is an 8-byte command value.  Commands which take params or
+ * return response data specify structs for that data.  If no struct is
+ * specified, the command does not input or output data, respectively.
+ * Parameter/response length is implicit in the structs.  Some underlying
+ * communication protocols (I2C, SPI) may add length or checksum headers, but
+ * those are implementation-dependent and not defined here.
+ */
+
+/*****************************************************************************/
+/* General / test commands */
+
+/*
+ * Get protocol version, used to deal with non-backward compatible protocol
+ * changes.
+ */
+#define EC_CMD_PROTO_VERSION 0x00
+
+struct ec_response_proto_version {
+	uint32_t version;
+} __packed;
+
+/*
+ * Hello.  This is a simple command to test the EC is responsive to
+ * commands.
+ */
+#define EC_CMD_HELLO 0x01
+
+struct ec_params_hello {
+	uint32_t in_data;  /* Pass anything here */
+} __packed;
+
+struct ec_response_hello {
+	uint32_t out_data;  /* Output will be in_data + 0x01020304 */
+} __packed;
+
+/* Get version number */
+#define EC_CMD_GET_VERSION 0x02
+
+enum ec_current_image {
+	EC_IMAGE_UNKNOWN = 0,
+	EC_IMAGE_RO,
+	EC_IMAGE_RW
+};
+
+struct ec_response_get_version {
+	/* Null-terminated version strings for RO, RW */
+	char version_string_ro[32];
+	char version_string_rw[32];
+	char reserved[32];       /* Was previously RW-B string */
+	uint32_t current_image;  /* One of ec_current_image */
+} __packed;
+
+/* Read test */
+#define EC_CMD_READ_TEST 0x03
+
+struct ec_params_read_test {
+	uint32_t offset;   /* Starting value for read buffer */
+	uint32_t size;     /* Size to read in bytes */
+} __packed;
+
+struct ec_response_read_test {
+	uint32_t data[32];
+} __packed;
+
+/*
+ * Get build information
+ *
+ * Response is null-terminated string.
+ */
+#define EC_CMD_GET_BUILD_INFO 0x04
+
+/* Get chip info */
+#define EC_CMD_GET_CHIP_INFO 0x05
+
+struct ec_response_get_chip_info {
+	/* Null-terminated strings */
+	char vendor[32];
+	char name[32];
+	char revision[32];  /* Mask version */
+} __packed;
+
+/* Get board HW version */
+#define EC_CMD_GET_BOARD_VERSION 0x06
+
+struct ec_response_board_version {
+	uint16_t board_version;  /* A monotonously incrementing number. */
+} __packed;
+
+/*
+ * Read memory-mapped data.
+ *
+ * This is an alternate interface to memory-mapped data for bus protocols
+ * which don't support direct-mapped memory - I2C, SPI, etc.
+ *
+ * Response is params.size bytes of data.
+ */
+#define EC_CMD_READ_MEMMAP 0x07
+
+struct ec_params_read_memmap {
+	uint8_t offset;   /* Offset in memmap (EC_MEMMAP_*) */
+	uint8_t size;     /* Size to read in bytes */
+} __packed;
+
+/* Read versions supported for a command */
+#define EC_CMD_GET_CMD_VERSIONS 0x08
+
+struct ec_params_get_cmd_versions {
+	uint8_t cmd;      /* Command to check */
+} __packed;
+
+struct ec_response_get_cmd_versions {
+	/*
+	 * Mask of supported versions; use EC_VER_MASK() to compare with a
+	 * desired version.
+	 */
+	uint32_t version_mask;
+} __packed;
+
+/*
+ * Check EC communcations status (busy). This is needed on i2c/spi but not
+ * on lpc since it has its own out-of-band busy indicator.
+ *
+ * lpc must read the status from the command register. Attempting this on
+ * lpc will overwrite the args/parameter space and corrupt its data.
+ */
+#define EC_CMD_GET_COMMS_STATUS		0x09
+
+/* Avoid using ec_status which is for return values */
+enum ec_comms_status {
+	EC_COMMS_STATUS_PROCESSING	= 1 << 0,	/* Processing cmd */
+};
+
+struct ec_response_get_comms_status {
+	uint32_t flags;		/* Mask of enum ec_comms_status */
+} __packed;
+
+
+/*****************************************************************************/
+/* Flash commands */
+
+/* Get flash info */
+#define EC_CMD_FLASH_INFO 0x10
+
+struct ec_response_flash_info {
+	/* Usable flash size, in bytes */
+	uint32_t flash_size;
+	/*
+	 * Write block size.  Write offset and size must be a multiple
+	 * of this.
+	 */
+	uint32_t write_block_size;
+	/*
+	 * Erase block size.  Erase offset and size must be a multiple
+	 * of this.
+	 */
+	uint32_t erase_block_size;
+	/*
+	 * Protection block size.  Protection offset and size must be a
+	 * multiple of this.
+	 */
+	uint32_t protect_block_size;
+} __packed;
+
+/*
+ * Read flash
+ *
+ * Response is params.size bytes of data.
+ */
+#define EC_CMD_FLASH_READ 0x11
+
+struct ec_params_flash_read {
+	uint32_t offset;   /* Byte offset to read */
+	uint32_t size;     /* Size to read in bytes */
+} __packed;
+
+/* Write flash */
+#define EC_CMD_FLASH_WRITE 0x12
+
+struct ec_params_flash_write {
+	uint32_t offset;   /* Byte offset to write */
+	uint32_t size;     /* Size to write in bytes */
+	/*
+	 * Data to write.  Could really use EC_PARAM_SIZE - 8, but tidiest to
+	 * use a power of 2 so writes stay aligned.
+	 */
+	uint8_t data[64];
+} __packed;
+
+/* Erase flash */
+#define EC_CMD_FLASH_ERASE 0x13
+
+struct ec_params_flash_erase {
+	uint32_t offset;   /* Byte offset to erase */
+	uint32_t size;     /* Size to erase in bytes */
+} __packed;
+
+/*
+ * Get/set flash protection.
+ *
+ * If mask!=0, sets/clear the requested bits of flags.  Depending on the
+ * firmware write protect GPIO, not all flags will take effect immediately;
+ * some flags require a subsequent hard reset to take effect.  Check the
+ * returned flags bits to see what actually happened.
+ *
+ * If mask=0, simply returns the current flags state.
+ */
+#define EC_CMD_FLASH_PROTECT 0x15
+#define EC_VER_FLASH_PROTECT 1  /* Command version 1 */
+
+/* Flags for flash protection */
+/* RO flash code protected when the EC boots */
+#define EC_FLASH_PROTECT_RO_AT_BOOT         (1 << 0)
+/*
+ * RO flash code protected now.  If this bit is set, at-boot status cannot
+ * be changed.
+ */
+#define EC_FLASH_PROTECT_RO_NOW             (1 << 1)
+/* Entire flash code protected now, until reboot. */
+#define EC_FLASH_PROTECT_ALL_NOW            (1 << 2)
+/* Flash write protect GPIO is asserted now */
+#define EC_FLASH_PROTECT_GPIO_ASSERTED      (1 << 3)
+/* Error -@least one bank of flash is stuck locked, and cannot be unlocked */
+#define EC_FLASH_PROTECT_ERROR_STUCK        (1 << 4)
+/*
+ * Error - flash protection is in inconsistent state.  At least one bank of
+ * flash which should be protected is not protected.  Usually fixed by
+ * re-requesting the desired flags, or by a hard reset if that fails.
+ */
+#define EC_FLASH_PROTECT_ERROR_INCONSISTENT (1 << 5)
+/* Entile flash code protected when the EC boots */
+#define EC_FLASH_PROTECT_ALL_AT_BOOT        (1 << 6)
+
+struct ec_params_flash_protect {
+	uint32_t mask;   /* Bits in flags to apply */
+	uint32_t flags;  /* New flags to apply */
+} __packed;
+
+struct ec_response_flash_protect {
+	/* Current value of flash protect flags */
+	uint32_t flags;
+	/*
+	 * Flags which are valid on this platform.  This allows the caller
+	 * to distinguish between flags which aren't set vs. flags which can't
+	 * be set on this platform.
+	 */
+	uint32_t valid_flags;
+	/* Flags which can be changed given the current protection state */
+	uint32_t writable_flags;
+} __packed;
+
+/*
+ * Note: commands 0x14 - 0x19 version 0 were old commands to get/set flash
+ * write protect.  These commands may be reused with version > 0.
+ */
+
+/* Get the region offset/size */
+#define EC_CMD_FLASH_REGION_INFO 0x16
+#define EC_VER_FLASH_REGION_INFO 1
+
+enum ec_flash_region {
+	/* Region which holds read-only EC image */
+	EC_FLASH_REGION_RO,
+	/* Region which holds rewritable EC image */
+	EC_FLASH_REGION_RW,
+	/*
+	 * Region which should be write-protected in the factory (a superset of
+	 * EC_FLASH_REGION_RO)
+	 */
+	EC_FLASH_REGION_WP_RO,
+};
+
+struct ec_params_flash_region_info {
+	uint32_t region;  /* enum ec_flash_region */
+} __packed;
+
+struct ec_response_flash_region_info {
+	uint32_t offset;
+	uint32_t size;
+} __packed;
+
+/* Read/write VbNvContext */
+#define EC_CMD_VBNV_CONTEXT 0x17
+#define EC_VER_VBNV_CONTEXT 1
+#define EC_VBNV_BLOCK_SIZE 16
+
+enum ec_vbnvcontext_op {
+	EC_VBNV_CONTEXT_OP_READ,
+	EC_VBNV_CONTEXT_OP_WRITE,
+};
+
+struct ec_params_vbnvcontext {
+	uint32_t op;
+	uint8_t block[EC_VBNV_BLOCK_SIZE];
+} __packed;
+
+struct ec_response_vbnvcontext {
+	uint8_t block[EC_VBNV_BLOCK_SIZE];
+} __packed;
+
+/*****************************************************************************/
+/* PWM commands */
+
+/* Get fan target RPM */
+#define EC_CMD_PWM_GET_FAN_TARGET_RPM 0x20
+
+struct ec_response_pwm_get_fan_rpm {
+	uint32_t rpm;
+} __packed;
+
+/* Set target fan RPM */
+#define EC_CMD_PWM_SET_FAN_TARGET_RPM 0x21
+
+struct ec_params_pwm_set_fan_target_rpm {
+	uint32_t rpm;
+} __packed;
+
+/* Get keyboard backlight */
+#define EC_CMD_PWM_GET_KEYBOARD_BACKLIGHT 0x22
+
+struct ec_response_pwm_get_keyboard_backlight {
+	uint8_t percent;
+	uint8_t enabled;
+} __packed;
+
+/* Set keyboard backlight */
+#define EC_CMD_PWM_SET_KEYBOARD_BACKLIGHT 0x23
+
+struct ec_params_pwm_set_keyboard_backlight {
+	uint8_t percent;
+} __packed;
+
+/* Set target fan PWM duty cycle */
+#define EC_CMD_PWM_SET_FAN_DUTY 0x24
+
+struct ec_params_pwm_set_fan_duty {
+	uint32_t percent;
+} __packed;
+
+/*****************************************************************************/
+/*
+ * Lightbar commands. This looks worse than it is. Since we only use one HOST
+ * command to say "talk to the lightbar", we put the "and tell it to do X" part
+ * into a subcommand. We'll make separate structs for subcommands with
+ * different input args, so that we know how much to expect.
+ */
+#define EC_CMD_LIGHTBAR_CMD 0x28
+
+struct rgb_s {
+	uint8_t r, g, b;
+};
+
+#define LB_BATTERY_LEVELS 4
+/* List of tweakable parameters. NOTE: It's __packed so it can be sent in a
+ * host command, but the alignment is the same regardless. Keep it that way.
+ */
+struct lightbar_params {
+	/* Timing */
+	int google_ramp_up;
+	int google_ramp_down;
+	int s3s0_ramp_up;
+	int s0_tick_delay[2];			/* AC=0/1 */
+	int s0a_tick_delay[2];			/* AC=0/1 */
+	int s0s3_ramp_down;
+	int s3_sleep_for;
+	int s3_ramp_up;
+	int s3_ramp_down;
+
+	/* Oscillation */
+	uint8_t new_s0;
+	uint8_t osc_min[2];			/* AC=0/1 */
+	uint8_t osc_max[2];			/* AC=0/1 */
+	uint8_t w_ofs[2];			/* AC=0/1 */
+
+	/* Brightness limits based on the backlight and AC. */
+	uint8_t bright_bl_off_fixed[2];		/* AC=0/1 */
+	uint8_t bright_bl_on_min[2];		/* AC=0/1 */
+	uint8_t bright_bl_on_max[2];		/* AC=0/1 */
+
+	/* Battery level thresholds */
+	uint8_t battery_threshold[LB_BATTERY_LEVELS - 1];
+
+	/* Map [AC][battery_level] to color index */
+	uint8_t s0_idx[2][LB_BATTERY_LEVELS];	/* AP is running */
+	uint8_t s3_idx[2][LB_BATTERY_LEVELS];	/* AP is sleeping */
+
+	/* Color palette */
+	struct rgb_s color[8];			/* 0-3 are Google colors */
+} __packed;
+
+struct ec_params_lightbar {
+	uint8_t cmd;		      /* Command (see enum lightbar_command) */
+	union {
+		struct {
+			/* no args */
+		} dump, off, on, init, get_seq, get_params;
+
+		struct num {
+			uint8_t num;
+		} brightness, seq, demo;
+
+		struct reg {
+			uint8_t ctrl, reg, value;
+		} reg;
+
+		struct rgb {
+			uint8_t led, red, green, blue;
+		} rgb;
+
+		struct lightbar_params set_params;
+	};
+} __packed;
+
+struct ec_response_lightbar {
+	union {
+		struct dump {
+			struct {
+				uint8_t reg;
+				uint8_t ic0;
+				uint8_t ic1;
+			} vals[23];
+		} dump;
+
+		struct get_seq {
+			uint8_t num;
+		} get_seq;
+
+		struct lightbar_params get_params;
+
+		struct {
+			/* no return params */
+		} off, on, init, brightness, seq, reg, rgb, demo, set_params;
+	};
+} __packed;
+
+/* Lightbar commands */
+enum lightbar_command {
+	LIGHTBAR_CMD_DUMP = 0,
+	LIGHTBAR_CMD_OFF = 1,
+	LIGHTBAR_CMD_ON = 2,
+	LIGHTBAR_CMD_INIT = 3,
+	LIGHTBAR_CMD_BRIGHTNESS = 4,
+	LIGHTBAR_CMD_SEQ = 5,
+	LIGHTBAR_CMD_REG = 6,
+	LIGHTBAR_CMD_RGB = 7,
+	LIGHTBAR_CMD_GET_SEQ = 8,
+	LIGHTBAR_CMD_DEMO = 9,
+	LIGHTBAR_CMD_GET_PARAMS = 10,
+	LIGHTBAR_CMD_SET_PARAMS = 11,
+	LIGHTBAR_NUM_CMDS
+};
+
+/*****************************************************************************/
+/* Verified boot commands */
+
+/*
+ * Note: command code 0x29 version 0 was VBOOT_CMD in Link EVT; it may be
+ * reused for other purposes with version > 0.
+ */
+
+/* Verified boot hash command */
+#define EC_CMD_VBOOT_HASH 0x2A
+
+struct ec_params_vboot_hash {
+	uint8_t cmd;             /* enum ec_vboot_hash_cmd */
+	uint8_t hash_type;       /* enum ec_vboot_hash_type */
+	uint8_t nonce_size;      /* Nonce size; may be 0 */
+	uint8_t reserved0;       /* Reserved; set 0 */
+	uint32_t offset;         /* Offset in flash to hash */
+	uint32_t size;           /* Number of bytes to hash */
+	uint8_t nonce_data[64];  /* Nonce data; ignored if nonce_size=0 */
+} __packed;
+
+struct ec_response_vboot_hash {
+	uint8_t status;          /* enum ec_vboot_hash_status */
+	uint8_t hash_type;       /* enum ec_vboot_hash_type */
+	uint8_t digest_size;     /* Size of hash digest in bytes */
+	uint8_t reserved0;       /* Ignore; will be 0 */
+	uint32_t offset;         /* Offset in flash which was hashed */
+	uint32_t size;           /* Number of bytes hashed */
+	uint8_t hash_digest[64]; /* Hash digest data */
+} __packed;
+
+enum ec_vboot_hash_cmd {
+	EC_VBOOT_HASH_GET = 0,       /* Get current hash status */
+	EC_VBOOT_HASH_ABORT = 1,     /* Abort calculating current hash */
+	EC_VBOOT_HASH_START = 2,     /* Start computing a new hash */
+	EC_VBOOT_HASH_RECALC = 3,    /* Synchronously compute a new hash */
+};
+
+enum ec_vboot_hash_type {
+	EC_VBOOT_HASH_TYPE_SHA256 = 0, /* SHA-256 */
+};
+
+enum ec_vboot_hash_status {
+	EC_VBOOT_HASH_STATUS_NONE = 0, /* No hash (not started, or aborted) */
+	EC_VBOOT_HASH_STATUS_DONE = 1, /* Finished computing a hash */
+	EC_VBOOT_HASH_STATUS_BUSY = 2, /* Busy computing a hash */
+};
+
+/*
+ * Special values for offset for EC_VBOOT_HASH_START and EC_VBOOT_HASH_RECALC.
+ * If one of these is specified, the EC will automatically update offset and
+ * size to the correct values for the specified image (RO or RW).
+ */
+#define EC_VBOOT_HASH_OFFSET_RO 0xfffffffe
+#define EC_VBOOT_HASH_OFFSET_RW 0xfffffffd
+
+/*****************************************************************************/
+/* USB charging control commands */
+
+/* Set USB port charging mode */
+#define EC_CMD_USB_CHARGE_SET_MODE 0x30
+
+struct ec_params_usb_charge_set_mode {
+	uint8_t usb_port_id;
+	uint8_t mode;
+} __packed;
+
+/*****************************************************************************/
+/* Persistent storage for host */
+
+/* Maximum bytes that can be read/written in a single command */
+#define EC_PSTORE_SIZE_MAX 64
+
+/* Get persistent storage info */
+#define EC_CMD_PSTORE_INFO 0x40
+
+struct ec_response_pstore_info {
+	/* Persistent storage size, in bytes */
+	uint32_t pstore_size;
+	/* Access size; read/write offset and size must be a multiple of this */
+	uint32_t access_size;
+} __packed;
+
+/*
+ * Read persistent storage
+ *
+ * Response is params.size bytes of data.
+ */
+#define EC_CMD_PSTORE_READ 0x41
+
+struct ec_params_pstore_read {
+	uint32_t offset;   /* Byte offset to read */
+	uint32_t size;     /* Size to read in bytes */
+} __packed;
+
+/* Write persistent storage */
+#define EC_CMD_PSTORE_WRITE 0x42
+
+struct ec_params_pstore_write {
+	uint32_t offset;   /* Byte offset to write */
+	uint32_t size;     /* Size to write in bytes */
+	uint8_t data[EC_PSTORE_SIZE_MAX];
+} __packed;
+
+/*****************************************************************************/
+/* Real-time clock */
+
+/* RTC params and response structures */
+struct ec_params_rtc {
+	uint32_t time;
+} __packed;
+
+struct ec_response_rtc {
+	uint32_t time;
+} __packed;
+
+/* These use ec_response_rtc */
+#define EC_CMD_RTC_GET_VALUE 0x44
+#define EC_CMD_RTC_GET_ALARM 0x45
+
+/* These all use ec_params_rtc */
+#define EC_CMD_RTC_SET_VALUE 0x46
+#define EC_CMD_RTC_SET_ALARM 0x47
+
+/*****************************************************************************/
+/* Port80 log access */
+
+/* Get last port80 code from previous boot */
+#define EC_CMD_PORT80_LAST_BOOT 0x48
+
+struct ec_response_port80_last_boot {
+	uint16_t code;
+} __packed;
+
+/*****************************************************************************/
+/* Thermal engine commands */
+
+/* Set thershold value */
+#define EC_CMD_THERMAL_SET_THRESHOLD 0x50
+
+struct ec_params_thermal_set_threshold {
+	uint8_t sensor_type;
+	uint8_t threshold_id;
+	uint16_t value;
+} __packed;
+
+/* Get threshold value */
+#define EC_CMD_THERMAL_GET_THRESHOLD 0x51
+
+struct ec_params_thermal_get_threshold {
+	uint8_t sensor_type;
+	uint8_t threshold_id;
+} __packed;
+
+struct ec_response_thermal_get_threshold {
+	uint16_t value;
+} __packed;
+
+/* Toggle automatic fan control */
+#define EC_CMD_THERMAL_AUTO_FAN_CTRL 0x52
+
+/* Get TMP006 calibration data */
+#define EC_CMD_TMP006_GET_CALIBRATION 0x53
+
+struct ec_params_tmp006_get_calibration {
+	uint8_t index;
+} __packed;
+
+struct ec_response_tmp006_get_calibration {
+	float s0;
+	float b0;
+	float b1;
+	float b2;
+} __packed;
+
+/* Set TMP006 calibration data */
+#define EC_CMD_TMP006_SET_CALIBRATION 0x54
+
+struct ec_params_tmp006_set_calibration {
+	uint8_t index;
+	uint8_t reserved[3];  /* Reserved; set 0 */
+	float s0;
+	float b0;
+	float b1;
+	float b2;
+} __packed;
+
+/*****************************************************************************/
+/* CROS_EC - Matrix KeyBoard Protocol */
+
+/*
+ * Read key state
+ *
+ * Returns raw data for keyboard cols; see ec_response_cros_ec_info.cols for
+ * expected response size.
+ */
+#define EC_CMD_CROS_EC_STATE 0x60
+
+/* Provide information about the matrix : number of rows and columns */
+#define EC_CMD_CROS_EC_INFO 0x61
+
+struct ec_response_cros_ec_info {
+	uint32_t rows;
+	uint32_t cols;
+	uint8_t switches;
+} __packed;
+
+/* Simulate key press */
+#define EC_CMD_CROS_EC_SIMULATE_KEY 0x62
+
+struct ec_params_cros_ec_simulate_key {
+	uint8_t col;
+	uint8_t row;
+	uint8_t pressed;
+} __packed;
+
+/* Configure keyboard scanning */
+#define EC_CMD_CROS_EC_SET_CONFIG 0x64
+#define EC_CMD_CROS_EC_GET_CONFIG 0x65
+
+/* flags */
+enum cros_ec_config_flags {
+	EC_CROS_EC_FLAGS_ENABLE = 1,	/* Enable keyboard scanning */
+};
+
+enum cros_ec_config_valid {
+	EC_CROS_EC_VALID_SCAN_PERIOD		= 1 << 0,
+	EC_CROS_EC_VALID_POLL_TIMEOUT		= 1 << 1,
+	EC_CROS_EC_VALID_MIN_POST_SCAN_DELAY	= 1 << 3,
+	EC_CROS_EC_VALID_OUTPUT_SETTLE		= 1 << 4,
+	EC_CROS_EC_VALID_DEBOUNCE_DOWN		= 1 << 5,
+	EC_CROS_EC_VALID_DEBOUNCE_UP		= 1 << 6,
+	EC_CROS_EC_VALID_FIFO_MAX_DEPTH		= 1 << 7,
+};
+
+/* Configuration for our key scanning algorithm */
+struct ec_cros_ec_config {
+	uint32_t valid_mask;		/* valid fields */
+	uint8_t flags;		/* some flags (enum cros_ec_config_flags) */
+	uint8_t valid_flags;		/* which flags are valid */
+	uint16_t scan_period_us;	/* period between start of scans */
+	/* revert to interrupt mode after no activity for this long */
+	uint32_t poll_timeout_us;
+	/*
+	 * minimum post-scan relax time. Once we finish a scan we check
+	 * the time until we are due to start the next one. If this time is
+	 * shorter this field, we use this instead.
+	 */
+	uint16_t min_post_scan_delay_us;
+	/* delay between setting up output and waiting for it to settle */
+	uint16_t output_settle_us;
+	uint16_t debounce_down_us;	/* time for debounce on key down */
+	uint16_t debounce_up_us;	/* time for debounce on key up */
+	/* maximum depth to allow for fifo (0 = no keyscan output) */
+	uint8_t fifo_max_depth;
+} __packed;
+
+struct ec_params_cros_ec_set_config {
+	struct ec_cros_ec_config config;
+} __packed;
+
+struct ec_response_cros_ec_get_config {
+	struct ec_cros_ec_config config;
+} __packed;
+
+/* Run the key scan emulation */
+#define EC_CMD_KEYSCAN_SEQ_CTRL 0x66
+
+enum ec_keyscan_seq_cmd {
+	EC_KEYSCAN_SEQ_STATUS = 0,	/* Get status information */
+	EC_KEYSCAN_SEQ_CLEAR = 1,	/* Clear sequence */
+	EC_KEYSCAN_SEQ_ADD = 2,		/* Add item to sequence */
+	EC_KEYSCAN_SEQ_START = 3,	/* Start running sequence */
+	EC_KEYSCAN_SEQ_COLLECT = 4,	/* Collect sequence summary data */
+};
+
+enum ec_collect_flags {
+	/*
+	 * Indicates this scan was processed by the EC. Due to timing, some
+	 * scans may be skipped.
+	 */
+	EC_KEYSCAN_SEQ_FLAG_DONE	= 1 << 0,
+};
+
+struct ec_collect_item {
+	uint8_t flags;		/* some flags (enum ec_collect_flags) */
+};
+
+struct ec_params_keyscan_seq_ctrl {
+	uint8_t cmd;	/* Command to send (enum ec_keyscan_seq_cmd) */
+	union {
+		struct {
+			uint8_t active;		/* still active */
+			uint8_t num_items;	/* number of items */
+			/* Current item being presented */
+			uint8_t cur_item;
+		} status;
+		struct {
+			/*
+			 * Absolute time for this scan, measured from the
+			 * start of the sequence.
+			 */
+			uint32_t time_us;
+			uint8_t scan[0];	/* keyscan data */
+		} add;
+		struct {
+			uint8_t start_item;	/* First item to return */
+			uint8_t num_items;	/* Number of items to return */
+		} collect;
+	};
+} __packed;
+
+struct ec_result_keyscan_seq_ctrl {
+	union {
+		struct {
+			uint8_t num_items;	/* Number of items */
+			/* Data for each item */
+			struct ec_collect_item item[0];
+		} collect;
+	};
+} __packed;
+
+/*****************************************************************************/
+/* Temperature sensor commands */
+
+/* Read temperature sensor info */
+#define EC_CMD_TEMP_SENSOR_GET_INFO 0x70
+
+struct ec_params_temp_sensor_get_info {
+	uint8_t id;
+} __packed;
+
+struct ec_response_temp_sensor_get_info {
+	char sensor_name[32];
+	uint8_t sensor_type;
+} __packed;
+
+/*****************************************************************************/
+
+/*
+ * Note: host commands 0x80 - 0x87 are reserved to avoid conflict with ACPI
+ * commands accidentally sent to the wrong interface.  See the ACPI section
+ * below.
+ */
+
+/*****************************************************************************/
+/* Host event commands */
+
+/*
+ * Host event mask params and response structures, shared by all of the host
+ * event commands below.
+ */
+struct ec_params_host_event_mask {
+	uint32_t mask;
+} __packed;
+
+struct ec_response_host_event_mask {
+	uint32_t mask;
+} __packed;
+
+/* These all use ec_response_host_event_mask */
+#define EC_CMD_HOST_EVENT_GET_B         0x87
+#define EC_CMD_HOST_EVENT_GET_SMI_MASK  0x88
+#define EC_CMD_HOST_EVENT_GET_SCI_MASK  0x89
+#define EC_CMD_HOST_EVENT_GET_WAKE_MASK 0x8d
+
+/* These all use ec_params_host_event_mask */
+#define EC_CMD_HOST_EVENT_SET_SMI_MASK  0x8a
+#define EC_CMD_HOST_EVENT_SET_SCI_MASK  0x8b
+#define EC_CMD_HOST_EVENT_CLEAR         0x8c
+#define EC_CMD_HOST_EVENT_SET_WAKE_MASK 0x8e
+#define EC_CMD_HOST_EVENT_CLEAR_B       0x8f
+
+/*****************************************************************************/
+/* Switch commands */
+
+/* Enable/disable LCD backlight */
+#define EC_CMD_SWITCH_ENABLE_BKLIGHT 0x90
+
+struct ec_params_switch_enable_backlight {
+	uint8_t enabled;
+} __packed;
+
+/* Enable/disable WLAN/Bluetooth */
+#define EC_CMD_SWITCH_ENABLE_WIRELESS 0x91
+
+struct ec_params_switch_enable_wireless {
+	uint8_t enabled;
+} __packed;
+
+/*****************************************************************************/
+/* GPIO commands. Only available on EC if write protect has been disabled. */
+
+/* Set GPIO output value */
+#define EC_CMD_GPIO_SET 0x92
+
+struct ec_params_gpio_set {
+	char name[32];
+	uint8_t val;
+} __packed;
+
+/* Get GPIO value */
+#define EC_CMD_GPIO_GET 0x93
+
+struct ec_params_gpio_get {
+	char name[32];
+} __packed;
+struct ec_response_gpio_get {
+	uint8_t val;
+} __packed;
+
+/*****************************************************************************/
+/* I2C commands. Only available when flash write protect is unlocked. */
+
+/* Read I2C bus */
+#define EC_CMD_I2C_READ 0x94
+
+struct ec_params_i2c_read {
+	uint16_t addr;
+	uint8_t read_size; /* Either 8 or 16. */
+	uint8_t port;
+	uint8_t offset;
+} __packed;
+struct ec_response_i2c_read {
+	uint16_t data;
+} __packed;
+
+/* Write I2C bus */
+#define EC_CMD_I2C_WRITE 0x95
+
+struct ec_params_i2c_write {
+	uint16_t data;
+	uint16_t addr;
+	uint8_t write_size; /* Either 8 or 16. */
+	uint8_t port;
+	uint8_t offset;
+} __packed;
+
+/*****************************************************************************/
+/* Charge state commands. Only available when flash write protect unlocked. */
+
+/* Force charge state machine to stop in idle mode */
+#define EC_CMD_CHARGE_FORCE_IDLE 0x96
+
+struct ec_params_force_idle {
+	uint8_t enabled;
+} __packed;
+
+/*****************************************************************************/
+/* Console commands. Only available when flash write protect is unlocked. */
+
+/* Snapshot console output buffer for use by EC_CMD_CONSOLE_READ. */
+#define EC_CMD_CONSOLE_SNAPSHOT 0x97
+
+/*
+ * Read next chunk of data from saved snapshot.
+ *
+ * Response is null-terminated string.  Empty string, if there is no more
+ * remaining output.
+ */
+#define EC_CMD_CONSOLE_READ 0x98
+
+/*****************************************************************************/
+
+/*
+ * Cut off battery power output if the battery supports.
+ *
+ * For unsupported battery, just don't implement this command and lets EC
+ * return EC_RES_INVALID_COMMAND.
+ */
+#define EC_CMD_BATTERY_CUT_OFF 0x99
+
+/*****************************************************************************/
+/* USB port mux control. */
+
+/*
+ * Switch USB mux or return to automatic switching.
+ */
+#define EC_CMD_USB_MUX 0x9a
+
+struct ec_params_usb_mux {
+	uint8_t mux;
+} __packed;
+
+/*****************************************************************************/
+/* LDOs / FETs control. */
+
+enum ec_ldo_state {
+	EC_LDO_STATE_OFF = 0,	/* the LDO / FET is shut down */
+	EC_LDO_STATE_ON = 1,	/* the LDO / FET is ON / providing power */
+};
+
+/*
+ * Switch on/off a LDO.
+ */
+#define EC_CMD_LDO_SET 0x9b
+
+struct ec_params_ldo_set {
+	uint8_t index;
+	uint8_t state;
+} __packed;
+
+/*
+ * Get LDO state.
+ */
+#define EC_CMD_LDO_GET 0x9c
+
+struct ec_params_ldo_get {
+	uint8_t index;
+} __packed;
+
+struct ec_response_ldo_get {
+	uint8_t state;
+} __packed;
+
+/*****************************************************************************/
+/* Temporary debug commands. TODO: remove this crosbug.com/p/13849 */
+
+/*
+ * Dump charge state machine context.
+ *
+ * Response is a binary dump of charge state machine context.
+ */
+#define EC_CMD_CHARGE_DUMP 0xa0
+
+/*
+ * Set maximum battery charging current.
+ */
+#define EC_CMD_CHARGE_CURRENT_LIMIT 0xa1
+
+struct ec_params_current_limit {
+	uint32_t limit;
+} __packed;
+
+/*****************************************************************************/
+/* Smart battery pass-through */
+
+/* Get / Set 16-bit smart battery registers */
+#define EC_CMD_SB_READ_WORD   0xb0
+#define EC_CMD_SB_WRITE_WORD  0xb1
+
+/* Get / Set string smart battery parameters
+ * formatted as SMBUS "block".
+ */
+#define EC_CMD_SB_READ_BLOCK  0xb2
+#define EC_CMD_SB_WRITE_BLOCK 0xb3
+
+struct ec_params_sb_rd {
+	uint8_t reg;
+} __packed;
+
+struct ec_response_sb_rd_word {
+	uint16_t value;
+} __packed;
+
+struct ec_params_sb_wr_word {
+	uint8_t reg;
+	uint16_t value;
+} __packed;
+
+struct ec_response_sb_rd_block {
+	uint8_t data[32];
+} __packed;
+
+struct ec_params_sb_wr_block {
+	uint8_t reg;
+	uint16_t data[32];
+} __packed;
+
+/*****************************************************************************/
+/* System commands */
+
+/*
+ * TODO: this is a confusing name, since it doesn't necessarily reboot the EC.
+ * Rename to "set image" or something similar.
+ */
+#define EC_CMD_REBOOT_EC 0xd2
+
+/* Command */
+enum ec_reboot_cmd {
+	EC_REBOOT_CANCEL = 0,        /* Cancel a pending reboot */
+	EC_REBOOT_JUMP_RO = 1,       /* Jump to RO without rebooting */
+	EC_REBOOT_JUMP_RW = 2,       /* Jump to RW without rebooting */
+	/* (command 3 was jump to RW-B) */
+	EC_REBOOT_COLD = 4,          /* Cold-reboot */
+	EC_REBOOT_DISABLE_JUMP = 5,  /* Disable jump until next reboot */
+	EC_REBOOT_HIBERNATE = 6      /* Hibernate EC */
+};
+
+/* Flags for ec_params_reboot_ec.reboot_flags */
+#define EC_REBOOT_FLAG_RESERVED0      (1 << 0)  /* Was recovery request */
+#define EC_REBOOT_FLAG_ON_AP_SHUTDOWN (1 << 1)  /* Reboot after AP shutdown */
+
+struct ec_params_reboot_ec {
+	uint8_t cmd;           /* enum ec_reboot_cmd */
+	uint8_t flags;         /* See EC_REBOOT_FLAG_* */
+} __packed;
+
+/*
+ * Get information on last EC panic.
+ *
+ * Returns variable-length platform-dependent panic information.  See panic.h
+ * for details.
+ */
+#define EC_CMD_GET_PANIC_INFO 0xd3
+
+/*****************************************************************************/
+/*
+ * ACPI commands
+ *
+ * These are valid ONLY on the ACPI command/data port.
+ */
+
+/*
+ * ACPI Read Embedded Controller
+ *
+ * This reads from ACPI memory space on the EC (EC_ACPI_MEM_*).
+ *
+ * Use the following sequence:
+ *
+ *    - Write EC_CMD_ACPI_READ to EC_LPC_ADDR_ACPI_CMD
+ *    - Wait for EC_LPC_CMDR_PENDING bit to clear
+ *    - Write address to EC_LPC_ADDR_ACPI_DATA
+ *    - Wait for EC_LPC_CMDR_DATA bit to set
+ *    - Read value from EC_LPC_ADDR_ACPI_DATA
+ */
+#define EC_CMD_ACPI_READ 0x80
+
+/*
+ * ACPI Write Embedded Controller
+ *
+ * This reads from ACPI memory space on the EC (EC_ACPI_MEM_*).
+ *
+ * Use the following sequence:
+ *
+ *    - Write EC_CMD_ACPI_WRITE to EC_LPC_ADDR_ACPI_CMD
+ *    - Wait for EC_LPC_CMDR_PENDING bit to clear
+ *    - Write address to EC_LPC_ADDR_ACPI_DATA
+ *    - Wait for EC_LPC_CMDR_PENDING bit to clear
+ *    - Write value to EC_LPC_ADDR_ACPI_DATA
+ */
+#define EC_CMD_ACPI_WRITE 0x81
+
+/*
+ * ACPI Query Embedded Controller
+ *
+ * This clears the lowest-order bit in the currently pending host events, and
+ * sets the result code to the 1-based index of the bit (event 0x00000001 = 1,
+ * event 0x80000000 = 32), or 0 if no event was pending.
+ */
+#define EC_CMD_ACPI_QUERY_EVENT 0x84
+
+/* Valid addresses in ACPI memory space, for read/write commands */
+/* Memory space version; set to EC_ACPI_MEM_VERSION_CURRENT */
+#define EC_ACPI_MEM_VERSION            0x00
+/*
+ * Test location; writing value here updates test compliment byte to (0xff -
+ * value).
+ */
+#define EC_ACPI_MEM_TEST               0x01
+/* Test compliment; writes here are ignored. */
+#define EC_ACPI_MEM_TEST_COMPLIMENT    0x02
+/* Keyboard backlight brightness percent (0 - 100) */
+#define EC_ACPI_MEM_KEYBOARD_BACKLIGHT 0x03
+
+/* Current version of ACPI memory address space */
+#define EC_ACPI_MEM_VERSION_CURRENT 1
+
+
+/*****************************************************************************/
+/*
+ * Special commands
+ *
+ * These do not follow the normal rules for commands.  See each command for
+ * details.
+ */
+
+/*
+ * Reboot NOW
+ *
+ * This command will work even when the EC LPC interface is busy, because the
+ * reboot command is processed@interrupt level.  Note that when the EC
+ * reboots, the host will reboot too, so there is no response to this command.
+ *
+ * Use EC_CMD_REBOOT_EC to reboot the EC more politely.
+ */
+#define EC_CMD_REBOOT 0xd1  /* Think "die" */
+
+/*
+ * Resend last response (not supported on LPC).
+ *
+ * Returns EC_RES_UNAVAILABLE if there is no response available - for example,
+ * there was no previous command, or the previous command's response was too
+ * big to save.
+ */
+#define EC_CMD_RESEND_RESPONSE 0xdb
+
+/*
+ * This header byte on a command indicate version 0. Any header byte less
+ * than this means that we are talking to an old EC which doesn't support
+ * versioning. In that case, we assume version 0.
+ *
+ * Header bytes greater than this indicate a later version. For example,
+ * EC_CMD_VERSION0 + 1 means we are using version 1.
+ *
+ * The old EC interface must not use commands 0dc or higher.
+ */
+#define EC_CMD_VERSION0 0xdc
+
+#endif  /* !__ACPI__ */
+
+#endif  /* __CROS_EC_COMMANDS_H */
diff --git a/include/fdtdec.h b/include/fdtdec.h
index 51ff266..0f4bbaa 100644
--- a/include/fdtdec.h
+++ b/include/fdtdec.h
@@ -78,6 +78,7 @@ enum fdt_compat_id {
 	COMPAT_SAMSUNG_EXYNOS5_SOUND,	/* Exynos Sound */
 	COMPAT_WOLFSON_WM8994_CODEC,	/* Wolfson WM8994 Sound Codec */
 	COMPAT_SAMSUNG_EXYNOS_SPI,	/* Exynos SPI */
+	COMPAT_GOOGLE_CROS_EC,		/* Google CROS_EC Protocol */
 	COMPAT_SAMSUNG_EXYNOS_EHCI,	/* Exynos EHCI controller */
 	COMPAT_SAMSUNG_EXYNOS_USB_PHY,	/* Exynos phy controller for usb2.0 */
 	COMPAT_MAXIM_MAX77686_PMIC,	/* MAX77686 PMIC */
diff --git a/lib/fdtdec.c b/lib/fdtdec.c
index 856f90c..24cd6f9 100644
--- a/lib/fdtdec.c
+++ b/lib/fdtdec.c
@@ -53,6 +53,7 @@ static const char * const compat_names[COMPAT_COUNT] = {
 	COMPAT(SAMSUNG_EXYNOS5_SOUND, "samsung,exynos-sound"),
 	COMPAT(WOLFSON_WM8994_CODEC, "wolfson,wm8994-codec"),
 	COMPAT(SAMSUNG_EXYNOS_SPI, "samsung,exynos-spi"),
+	COMPAT(GOOGLE_CROS_EC, "google,cros-ec"),
 	COMPAT(SAMSUNG_EXYNOS_EHCI, "samsung,exynos-ehci"),
 	COMPAT(SAMSUNG_EXYNOS_USB_PHY, "samsung,exynos-usb-phy"),
 	COMPAT(MAXIM_MAX77686_PMIC, "maxim,max77686_pmic"),
-- 
1.8.1.3

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [U-Boot] [PATCH v4 2/7] cros: add I2C support for cros_ec
  2013-04-02 10:01 [U-Boot] [PATCH v4 0/7] Add cros-ec protocol driver and enable it in smdk5250 Hung-ying Tyan
  2013-04-02 10:01 ` [U-Boot] [PATCH v4 1/7] cros: add cros_ec driver Hung-ying Tyan
@ 2013-04-02 10:01 ` Hung-ying Tyan
  2013-04-04 20:14   ` Simon Glass
  2013-04-02 10:01 ` [U-Boot] [PATCH v4 3/7] cros: add SPI " Hung-ying Tyan
                   ` (6 subsequent siblings)
  8 siblings, 1 reply; 18+ messages in thread
From: Hung-ying Tyan @ 2013-04-02 10:01 UTC (permalink / raw)
  To: u-boot

This patch adds I2C support for carrying out the cros_ec protocol.

Signed-off-by: Randall Spangler <rspangler@chromium.org>
Signed-off-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Hung-ying Tyan <tyanh@chromium.org>

---
Changes in v4: None
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_i2c.c | 199 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 200 insertions(+)
 create mode 100644 drivers/misc/cros_ec_i2c.c

diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 33fe822..9363ef9 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -31,6 +31,7 @@ COBJS-$(CONFIG_CBMEM_CONSOLE) += cbmem_console.o
 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_NS87308) += ns87308.o
 COBJS-$(CONFIG_PDSP188x) += pdsp188x.o
 COBJS-$(CONFIG_STATUS_LED) += status_led.o
diff --git a/drivers/misc/cros_ec_i2c.c b/drivers/misc/cros_ec_i2c.c
new file mode 100644
index 0000000..b0060ac
--- /dev/null
+++ b/drivers/misc/cros_ec_i2c.c
@@ -0,0 +1,199 @@
+/*
+ * Chromium OS cros_ec driver - I2C 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 <common.h>
+#include <i2c.h>
+#include <cros_ec.h>
+
+#ifdef DEBUG_TRACE
+#define debug_trace(fmt, b...)	debug(fmt, #b)
+#else
+#define debug_trace(fmt, b...)
+#endif
+
+int cros_ec_i2c_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 old_bus = 0;
+	/* version8, cmd8, arglen8, out8[dout_len], csum8 */
+	int out_bytes = dout_len + 4;
+	/* response8, arglen8, in8[din_len], checksum8 */
+	int in_bytes = din_len + 3;
+	uint8_t *ptr;
+	/* Receive input data, so that args will be dword aligned */
+	uint8_t *in_ptr;
+	int ret;
+
+	old_bus = i2c_get_bus_num();
+
+	/*
+	 * Sanity-check I/O sizes given transaction overhead in internal
+	 * buffers.
+	 */
+	if (out_bytes > sizeof(dev->dout)) {
+		debug("%s: Cannot send %d bytes\n", __func__, dout_len);
+		return -1;
+	}
+	if (in_bytes > sizeof(dev->din)) {
+		debug("%s: Cannot receive %d bytes\n", __func__, din_len);
+		return -1;
+	}
+	assert(dout_len >= 0);
+	assert(dinp);
+
+	/*
+	 * Copy command and data into output buffer so we can do a single I2C
+	 * burst transaction.
+	 */
+	ptr = dev->dout;
+
+	/*
+	 * in_ptr starts of pointing to a dword-aligned input data buffer.
+	 * We decrement it back by the number of header bytes we expect to
+	 * receive, so that the first parameter of the resulting input data
+	 * will be dword aligned.
+	 */
+	in_ptr = dev->din + sizeof(int64_t);
+	if (!dev->cmd_version_is_supported) {
+		/* Send an old-style command */
+		*ptr++ = cmd;
+		out_bytes = dout_len + 1;
+		in_bytes = din_len + 2;
+		in_ptr--;	/* Expect just a status byte */
+	} else {
+		*ptr++ = EC_CMD_VERSION0 + cmd_version;
+		*ptr++ = cmd;
+		*ptr++ = dout_len;
+		in_ptr -= 2;	/* Expect status, length bytes */
+	}
+	memcpy(ptr, dout, dout_len);
+	ptr += dout_len;
+
+	if (dev->cmd_version_is_supported)
+		*ptr++ = (uint8_t)
+			 cros_ec_calc_checksum(dev->dout, dout_len + 3);
+
+	/* Set to the proper i2c bus */
+	if (i2c_set_bus_num(dev->bus_num)) {
+		debug("%s: Cannot change to I2C bus %d\n", __func__,
+			dev->bus_num);
+		return -1;
+	}
+
+	/* Send output data */
+	cros_ec_dump_data("out", -1, dev->dout, out_bytes);
+	ret = i2c_write(dev->addr, 0, 0, dev->dout, out_bytes);
+	if (ret) {
+		debug("%s: Cannot complete I2C write to 0x%x\n",
+			__func__, dev->addr);
+		ret = -1;
+	}
+
+	if (!ret) {
+		ret = i2c_read(dev->addr, 0, 0, in_ptr, in_bytes);
+		if (ret) {
+			debug("%s: Cannot complete I2C read from 0x%x\n",
+				__func__, dev->addr);
+			ret = -1;
+		}
+	}
+
+	/* Return to original bus number */
+	i2c_set_bus_num(old_bus);
+	if (ret)
+		return ret;
+
+	if (*in_ptr != EC_RES_SUCCESS) {
+		debug("%s: Received bad result code %d\n", __func__, *in_ptr);
+		return -(int)*in_ptr;
+	}
+
+	if (dev->cmd_version_is_supported) {
+		int len, csum;
+
+		len = in_ptr[1];
+		if (len + 3 > sizeof(dev->din)) {
+			debug("%s: Received length %#02x too large\n",
+			      __func__, len);
+			return -1;
+		}
+		csum = cros_ec_calc_checksum(in_ptr, 2 + len);
+		if (csum != in_ptr[2 + len]) {
+			debug("%s: Invalid checksum rx %#02x, calced %#02x\n",
+			      __func__, in_ptr[2 + din_len], csum);
+			return -1;
+		}
+		din_len = min(din_len, len);
+		cros_ec_dump_data("in", -1, in_ptr, din_len + 3);
+	} else {
+		cros_ec_dump_data("in (old)", -1, in_ptr, in_bytes);
+	}
+
+	/* Return pointer to dword-aligned input data, if any */
+	*dinp = dev->din + sizeof(int64_t);
+
+	return din_len;
+}
+
+int cros_ec_i2c_decode_fdt(struct cros_ec_dev *dev, const void *blob)
+{
+	/* Decode interface-specific FDT params */
+	dev->max_frequency = fdtdec_get_int(blob, dev->node,
+					    "i2c-max-frequency", 100000);
+	dev->bus_num = i2c_get_bus_num_fdt(dev->parent_node);
+	if (dev->bus_num == -1) {
+		debug("%s: Failed to read bus number\n", __func__);
+		return -1;
+	}
+	dev->addr = fdtdec_get_int(blob, dev->node, "reg", -1);
+	if (dev->addr == -1) {
+		debug("%s: Failed to read device address\n", __func__);
+		return -1;
+	}
+
+	return 0;
+}
+
+/**
+ * Initialize I2C protocol.
+ *
+ * @param dev		CROS_EC device
+ * @param blob		Device tree blob
+ * @return 0 if ok, -1 on error
+ */
+int cros_ec_i2c_init(struct cros_ec_dev *dev, const void *blob)
+{
+	i2c_init(dev->max_frequency, dev->addr);
+
+	dev->cmd_version_is_supported = 0;
+
+	return 0;
+}
-- 
1.8.1.3

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [U-Boot] [PATCH v4 3/7] cros: add SPI support for cros_ec
  2013-04-02 10:01 [U-Boot] [PATCH v4 0/7] Add cros-ec protocol driver and enable it in smdk5250 Hung-ying Tyan
  2013-04-02 10:01 ` [U-Boot] [PATCH v4 1/7] cros: add cros_ec driver Hung-ying Tyan
  2013-04-02 10:01 ` [U-Boot] [PATCH v4 2/7] cros: add I2C support for cros_ec Hung-ying Tyan
@ 2013-04-02 10:01 ` Hung-ying Tyan
  2013-04-04 20:14   ` Simon Glass
  2013-04-02 10:01 ` [U-Boot] [PATCH v4 4/7] cros: add LPC " Hung-ying Tyan
                   ` (5 subsequent siblings)
  8 siblings, 1 reply; 18+ messages in thread
From: Hung-ying Tyan @ 2013-04-02 10:01 UTC (permalink / raw)
  To: u-boot

This patch adds SPI support for carrying out the cros_ec protocol.

Signed-off-by: Hung-ying Tyan <tyanh@chromium.org>
Signed-off-by: Randall Spangler <rspangler@chromium.org>
Signed-off-by: Simon Glass <sjg@chromium.org>

---
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 <common.h>
+#include <cros_ec.h>
+#include <spi.h>
+
+/**
+ * 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_ */
-- 
1.8.1.3

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [U-Boot] [PATCH v4 4/7] cros: add LPC support for cros_ec
  2013-04-02 10:01 [U-Boot] [PATCH v4 0/7] Add cros-ec protocol driver and enable it in smdk5250 Hung-ying Tyan
                   ` (2 preceding siblings ...)
  2013-04-02 10:01 ` [U-Boot] [PATCH v4 3/7] cros: add SPI " Hung-ying Tyan
@ 2013-04-02 10:01 ` Hung-ying Tyan
  2013-04-04 20:15   ` Simon Glass
  2013-04-02 10:01 ` [U-Boot] [PATCH v4 5/7] cros: adds cros_ec keyboard driver Hung-ying Tyan
                   ` (4 subsequent siblings)
  8 siblings, 1 reply; 18+ messages in thread
From: Hung-ying Tyan @ 2013-04-02 10:01 UTC (permalink / raw)
  To: u-boot

This patch adds LPC support for carrying out the cros_ec protocol.

Signed-off-by: Randall Spangler <rspangler@chromium.org>
Signed-off-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Hung-ying Tyan <tyanh@chromium.org>

---
Changes in v4: None
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_lpc.c | 283 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 284 insertions(+)
 create mode 100644 drivers/misc/cros_ec_lpc.c

diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 18209ec..3553ff6 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -31,6 +31,7 @@ COBJS-$(CONFIG_CBMEM_CONSOLE) += cbmem_console.o
 COBJS-$(CONFIG_GPIO_LED) += gpio_led.o
 COBJS-$(CONFIG_FSL_MC9SDZ60) += mc9sdz60.o
 COBJS-$(CONFIG_CROS_EC) += cros_ec.o
+COBJS-$(CONFIG_CROS_EC_LPC) += cros_ec_lpc.o
 COBJS-$(CONFIG_CROS_EC_I2C) += cros_ec_i2c.o
 COBJS-$(CONFIG_CROS_EC_SPI) += cros_ec_spi.o
 COBJS-$(CONFIG_NS87308) += ns87308.o
diff --git a/drivers/misc/cros_ec_lpc.c b/drivers/misc/cros_ec_lpc.c
new file mode 100644
index 0000000..cf0435b
--- /dev/null
+++ b/drivers/misc/cros_ec_lpc.c
@@ -0,0 +1,283 @@
+/*
+ * Chromium OS cros_ec driver - LPC 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 <common.h>
+#include <command.h>
+#include <cros_ec.h>
+#include <asm/io.h>
+
+#ifdef DEBUG_TRACE
+#define debug_trace(fmt, b...)	debug(fmt, ##b)
+#else
+#define debug_trace(fmt, b...)
+#endif
+
+static int wait_for_sync(struct cros_ec_dev *dev)
+{
+	unsigned long start;
+
+	start = get_timer(0);
+	while (inb(EC_LPC_ADDR_HOST_CMD) & EC_LPC_STATUS_BUSY_MASK) {
+		if (get_timer(start) > 1000) {
+			debug("%s: Timeout waiting for CROS_EC sync\n",
+			      __func__);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * 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          Place to put pointer to response data
+ * @param din_len       Maximum size of response in bytes
+ * @return number of bytes in response, or -1 on error
+ */
+static int old_lpc_command(struct cros_ec_dev *dev, uint8_t cmd,
+		     const uint8_t *dout, int dout_len,
+		     uint8_t **dinp, int din_len)
+{
+	int ret, i;
+
+	if (dout_len > EC_OLD_PARAM_SIZE) {
+		debug("%s: Cannot send %d bytes\n", __func__, dout_len);
+		return -1;
+	}
+
+	if (din_len > EC_OLD_PARAM_SIZE) {
+		debug("%s: Cannot receive %d bytes\n", __func__, din_len);
+		return -1;
+	}
+
+	if (wait_for_sync(dev)) {
+		debug("%s: Timeout waiting ready\n", __func__);
+		return -1;
+	}
+
+	debug_trace("cmd: %02x, ", cmd);
+	for (i = 0; i < dout_len; i++) {
+		debug_trace("%02x ", dout[i]);
+		outb(dout[i], EC_LPC_ADDR_OLD_PARAM + i);
+	}
+	outb(cmd, EC_LPC_ADDR_HOST_CMD);
+	debug_trace("\n");
+
+	if (wait_for_sync(dev)) {
+		debug("%s: Timeout waiting ready\n", __func__);
+		return -1;
+	}
+
+	ret = inb(EC_LPC_ADDR_HOST_DATA);
+	if (ret) {
+		debug("%s: CROS_EC result code %d\n", __func__, ret);
+		return -ret;
+	}
+
+	debug_trace("resp: %02x, ", ret);
+	for (i = 0; i < din_len; i++) {
+		dev->din[i] = inb(EC_LPC_ADDR_OLD_PARAM + i);
+		debug_trace("%02x ", dev->din[i]);
+	}
+	debug_trace("\n");
+	*dinp = dev->din;
+
+	return din_len;
+}
+
+int cros_ec_lpc_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)
+{
+	const int cmd_addr = EC_LPC_ADDR_HOST_CMD;
+	const int data_addr = EC_LPC_ADDR_HOST_DATA;
+	const int args_addr = EC_LPC_ADDR_HOST_ARGS;
+	const int param_addr = EC_LPC_ADDR_HOST_PARAM;
+
+	struct ec_lpc_host_args args;
+	uint8_t *d;
+	int csum;
+	int i;
+
+	/* Fall back to old-style command interface if args aren't supported */
+	if (!dev->cmd_version_is_supported)
+		return old_lpc_command(dev, cmd, dout, dout_len, dinp,
+				       din_len);
+
+	if (dout_len > EC_HOST_PARAM_SIZE) {
+		debug("%s: Cannot send %d bytes\n", __func__, dout_len);
+		return -1;
+	}
+
+	/* Fill in args */
+	args.flags = EC_HOST_ARGS_FLAG_FROM_HOST;
+	args.command_version = cmd_version;
+	args.data_size = dout_len;
+
+	/* Calculate checksum */
+	csum = cmd + args.flags + args.command_version + args.data_size;
+	for (i = 0, d = (uint8_t *)dout; i < dout_len; i++, d++)
+		csum += *d;
+
+	args.checksum = (uint8_t)csum;
+
+	if (wait_for_sync(dev)) {
+		debug("%s: Timeout waiting ready\n", __func__);
+		return -1;
+	}
+
+	/* Write args */
+	for (i = 0, d = (uint8_t *)&args; i < sizeof(args); i++, d++)
+		outb(*d, args_addr + i);
+
+	/* Write data, if any */
+	debug_trace("cmd: %02x, ver: %02x", cmd, cmd_version);
+	for (i = 0, d = (uint8_t *)dout; i < dout_len; i++, d++) {
+		outb(*d, param_addr + i);
+		debug_trace("%02x ", *d);
+	}
+
+	outb(cmd, cmd_addr);
+	debug_trace("\n");
+
+	if (wait_for_sync(dev)) {
+		debug("%s: Timeout waiting for response\n", __func__);
+		return -1;
+	}
+
+	/* Check result */
+	i = inb(data_addr);
+	if (i) {
+		debug("%s: CROS_EC result code %d\n", __func__, i);
+		return -i;
+	}
+
+	/* Read back args */
+	for (i = 0, d = (uint8_t *)&args; i < sizeof(args); i++, d++)
+		*d = inb(args_addr + i);
+
+	/*
+	 * If EC didn't modify args flags, then somehow we sent a new-style
+	 * command to an old EC, which means it would have read its params
+	 * from the wrong place.
+	 */
+	if (!(args.flags & EC_HOST_ARGS_FLAG_TO_HOST)) {
+		debug("%s: CROS_EC protocol mismatch\n", __func__);
+		return -EC_RES_INVALID_RESPONSE;
+	}
+
+	if (args.data_size > din_len) {
+		debug("%s: CROS_EC returned too much data %d > %d\n",
+		      __func__, args.data_size, din_len);
+		return -EC_RES_INVALID_RESPONSE;
+	}
+
+	/* Read data, if any */
+	for (i = 0, d = (uint8_t *)dev->din; i < args.data_size; i++, d++) {
+		*d = inb(param_addr + i);
+		debug_trace("%02x ", *d);
+	}
+	debug_trace("\n");
+
+	/* Verify checksum */
+	csum = cmd + args.flags + args.command_version + args.data_size;
+	for (i = 0, d = (uint8_t *)dev->din; i < args.data_size; i++, d++)
+		csum += *d;
+
+	if (args.checksum != (uint8_t)csum) {
+		debug("%s: CROS_EC response has invalid checksum\n", __func__);
+		return -EC_RES_INVALID_CHECKSUM;
+	}
+	*dinp = dev->din;
+
+	/* Return actual amount of data received */
+	return args.data_size;
+}
+
+/**
+ * Initialize LPC protocol.
+ *
+ * @param dev		CROS_EC device
+ * @param blob		Device tree blob
+ * @return 0 if ok, -1 on error
+ */
+int cros_ec_lpc_init(struct cros_ec_dev *dev, const void *blob)
+{
+	int byte, i;
+
+	/* See if we can find an EC at the other end */
+	byte = 0xff;
+	byte &= inb(EC_LPC_ADDR_HOST_CMD);
+	byte &= inb(EC_LPC_ADDR_HOST_DATA);
+	for (i = 0; i < EC_HOST_PARAM_SIZE && (byte == 0xff); i++)
+		byte &= inb(EC_LPC_ADDR_HOST_PARAM + i);
+	if (byte == 0xff) {
+		debug("%s: CROS_EC device not found on LPC bus\n",
+			__func__);
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * Test if LPC command args are supported.
+ *
+ * The cheapest way to do this is by looking for the memory-mapped
+ * flag.  This is faster than sending a new-style 'hello' command and
+ * seeing whether the EC sets the EC_HOST_ARGS_FLAG_FROM_HOST flag
+ * in args when it responds.
+ */
+int cros_ec_lpc_check_version(struct cros_ec_dev *dev)
+{
+	if (inb(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_ID) == 'E' &&
+			inb(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_ID + 1)
+				== 'C' &&
+			(inb(EC_LPC_ADDR_MEMMAP +
+				EC_MEMMAP_HOST_CMD_FLAGS) &
+				EC_HOST_CMD_FLAG_LPC_ARGS_SUPPORTED)) {
+		dev->cmd_version_is_supported = 1;
+	} else {
+		/* We are going to use the old IO ports */
+		dev->cmd_version_is_supported = 0;
+	}
+	debug("lpc: version %s\n", dev->cmd_version_is_supported ?
+			"new" : "old");
+
+	return 0;
+}
-- 
1.8.1.3

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [U-Boot] [PATCH v4 5/7] cros: adds cros_ec keyboard driver
  2013-04-02 10:01 [U-Boot] [PATCH v4 0/7] Add cros-ec protocol driver and enable it in smdk5250 Hung-ying Tyan
                   ` (3 preceding siblings ...)
  2013-04-02 10:01 ` [U-Boot] [PATCH v4 4/7] cros: add LPC " Hung-ying Tyan
@ 2013-04-02 10:01 ` Hung-ying Tyan
  2013-04-04 20:15   ` Simon Glass
  2013-04-02 10:01 ` [U-Boot] [PATCH v4 6/7] cros: exynos: add cros-ec device nodes to exynos5250-snow.dts Hung-ying Tyan
                   ` (3 subsequent siblings)
  8 siblings, 1 reply; 18+ messages in thread
From: Hung-ying Tyan @ 2013-04-02 10:01 UTC (permalink / raw)
  To: u-boot

This patch adds the driver for keyboard that's controlled by ChromeOS EC.

Signed-off-by: Randall Spangler <rspangler@chromium.org>
Signed-off-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Vincent Palatin <vpalatin@chromium.org>
Signed-off-by: Hung-ying Tyan <tyanh@chromium.org>

---
Changes in v4:
- Added cros-ec-keyb.txt.

Changes in v3:
- Rearranged #include directives in alphabetical order.
- Removed outdated TODO and irrelevant bug reference in comments.

Changes in v2:
- Fixed warnings of exceeding 80 chars in a line.
- Added commit message.
- Dropped the period from commit subject.

 README                                          |   5 +
 doc/device-tree-bindings/input/cros-ec-keyb.txt |  79 +++++++
 drivers/input/Makefile                          |   1 +
 drivers/input/cros_ec_keyb.c                    | 261 ++++++++++++++++++++++++
 include/fdtdec.h                                |   1 +
 lib/fdtdec.c                                    |   1 +
 6 files changed, 348 insertions(+)
 create mode 100644 doc/device-tree-bindings/input/cros-ec-keyb.txt
 create mode 100644 drivers/input/cros_ec_keyb.c

diff --git a/README b/README
index 42544ce..769d1bf 100644
--- a/README
+++ b/README
@@ -1371,6 +1371,11 @@ CBFS (Coreboot Filesystem) support
 		Export function i8042_kbd_init, i8042_tstc and i8042_getc
 		for cfb_console. Supports cursor blinking.
 
+		CONFIG_CROS_EC_KEYB
+		Enables a Chrome OS keyboard using the CROS_EC interface.
+		This uses CROS_EC to communicate with a second microcontroller
+		which provides key scans on request.
+
 - Video support:
 		CONFIG_VIDEO
 
diff --git a/doc/device-tree-bindings/input/cros-ec-keyb.txt b/doc/device-tree-bindings/input/cros-ec-keyb.txt
new file mode 100644
index 0000000..3118276
--- /dev/null
+++ b/doc/device-tree-bindings/input/cros-ec-keyb.txt
@@ -0,0 +1,79 @@
+CROS_EC Keyboard
+
+The CROS_EC (Matrix Keyboard Protocol) allows communcation with a secondary
+micro used for keyboard, and possible other features.
+
+The CROS_EC keyboard uses this protocol to receive key scans and produce input
+in U-Boot.
+
+Required properties :
+- compatible : "google,cros-ec-keyb"
+- google,key-rows : Number of key rows
+- google,key-columns : Number of key columns
+
+Optional properties, in addition to those specified by the shared
+matrix-keyboard bindings:
+
+- linux,fn-keymap: a second keymap, same specification as the
+  matrix-keyboard-controller spec but to be used when the KEY_FN modifier
+  key is pressed.
+- google,repeat-delay-ms : delay in milliseconds before repeat starts
+- google,repeat-rate-ms : delay between each subsequent key press
+- google,ghost-filter : enable ghost filtering for this device
+
+Example, taken from daisy:
+
+cros-ec-keyb {
+	compatible = "google,cros-ec-keyb";
+	google,key-rows = <8>;
+	google,key-columns = <13>;
+	google,ghost-filter;
+	google,repeat-delay-ms = <240>;
+	google,repeat-rate-ms = <30>;
+	/*
+		* Keymap entries take the form of 0xRRCCKKKK where
+		* RR=Row CC=Column KKKK=Key Code
+		* The values below are for a US keyboard layout and
+		* are taken from the Linux driver. Note that the
+		* 102ND key is not used for US keyboards.
+		*/
+	linux,keymap = <
+		/* CAPSLCK F1         B          F10     */
+		0x0001003a 0x0002003c 0x00030030 0x00040044
+		/* N       =          R_ALT      ESC     */
+		0x00060031 0x0008000d 0x000a0064 0x01010001
+		/* F4      G          F7         H       */
+		0x0102003e 0x01030022 0x01040041 0x01060023
+		/* '       F9         BKSPACE    L_CTRL  */
+		0x01080028 0x01090043 0x010b000e 0x0200001d
+		/* TAB     F3         T          F6      */
+		0x0201000f 0x0202003d 0x02030014 0x02040040
+		/* ]       Y          102ND      [       */
+		0x0205001b 0x02060015 0x02070056 0x0208001a
+		/* F8      GRAVE      F2         5       */
+		0x02090042 0x03010029 0x0302003c 0x03030006
+		/* F5      6          -          \       */
+		0x0304003f 0x03060007 0x0308000c 0x030b002b
+		/* R_CTRL  A          D          F       */
+		0x04000061 0x0401001e 0x04020020 0x04030021
+		/* S       K          J          ;       */
+		0x0404001f 0x04050025 0x04060024 0x04080027
+		/* L       ENTER      Z          C       */
+		0x04090026 0x040b001c 0x0501002c 0x0502002e
+		/* V       X          ,          M       */
+		0x0503002f 0x0504002d 0x05050033 0x05060032
+		/* L_SHIFT /          .          SPACE   */
+		0x0507002a 0x05080035 0x05090034 0x050B0039
+		/* 1       3          4          2       */
+		0x06010002 0x06020004 0x06030005 0x06040003
+		/* 8       7          0          9       */
+		0x06050009 0x06060008 0x0608000b 0x0609000a
+		/* L_ALT   DOWN       RIGHT      Q       */
+		0x060a0038 0x060b006c 0x060c006a 0x07010010
+		/* E       R          W          I       */
+		0x07020012 0x07030013 0x07040011 0x07050017
+		/* U       R_SHIFT    P          O       */
+		0x07060016 0x07070036 0x07080019 0x07090018
+		/* UP      LEFT    */
+		0x070b0067 0x070c0069>;
+};
diff --git a/drivers/input/Makefile b/drivers/input/Makefile
index 0805e86..4331190 100644
--- a/drivers/input/Makefile
+++ b/drivers/input/Makefile
@@ -27,6 +27,7 @@ LIB	:= $(obj)libinput.o
 
 COBJS-$(CONFIG_I8042_KBD) += i8042.o
 COBJS-$(CONFIG_TEGRA_KEYBOARD) += tegra-kbc.o
+COBJS-$(CONFIG_CROS_EC_KEYB) += cros_ec_keyb.o
 ifdef CONFIG_PS2KBD
 COBJS-y += keyboard.o pc_keyb.o
 COBJS-$(CONFIG_PS2MULT) += ps2mult.o ps2ser.o
diff --git a/drivers/input/cros_ec_keyb.c b/drivers/input/cros_ec_keyb.c
new file mode 100644
index 0000000..c197308
--- /dev/null
+++ b/drivers/input/cros_ec_keyb.c
@@ -0,0 +1,261 @@
+/*
+ * Chromium OS Matrix Keyboard
+ *
+ * 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
+ */
+
+#include <common.h>
+#include <cros_ec.h>
+#include <fdtdec.h>
+#include <input.h>
+#include <key_matrix.h>
+#include <stdio_dev.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+enum {
+	KBC_MAX_KEYS		= 8,	/* Maximum keys held down at once */
+};
+
+static struct keyb {
+	struct cros_ec_dev *dev;		/* The CROS_EC device */
+	struct input_config input;	/* The input layer */
+	struct key_matrix matrix;	/* The key matrix layer */
+	int key_rows;			/* Number of keyboard rows */
+	int key_cols;			/* Number of keyboard columns */
+	unsigned int repeat_delay_ms;	/* Time before autorepeat starts */
+	unsigned int repeat_rate_ms;	/* Autorepeat rate in ms */
+	int ghost_filter;		/* 1 to enable ghost filter, else 0 */
+	int inited;			/* 1 if keyboard is ready */
+} config;
+
+
+/**
+ * Check the keyboard controller and return a list of key matrix positions
+ * for which a key is pressed
+ *
+ * @param config	Keyboard config
+ * @param keys		List of keys that we have detected
+ * @param max_count	Maximum number of keys to return
+ * @return number of pressed keys, 0 for none
+ */
+static int check_for_keys(struct keyb *config,
+			   struct key_matrix_key *keys, int max_count)
+{
+	struct key_matrix_key *key;
+	struct mbkp_keyscan scan;
+	unsigned int row, col, bit, data;
+	int num_keys;
+
+	if (cros_ec_scan_keyboard(config->dev, &scan)) {
+		debug("%s: keyboard scan failed\n", __func__);
+		return -1;
+	}
+
+	for (col = num_keys = bit = 0; col < config->matrix.num_cols;
+			col++) {
+		for (row = 0; row < config->matrix.num_rows; row++) {
+			unsigned int mask = 1 << (bit & 7);
+
+			data = scan.data[bit / 8];
+			if ((data & mask) && num_keys < max_count) {
+				key = keys + num_keys++;
+				key->row = row;
+				key->col = col;
+				key->valid = 1;
+			}
+			bit++;
+		}
+	}
+
+	return num_keys;
+}
+
+/**
+ * Test if keys are available to be read
+ *
+ * @return 0 if no keys available, 1 if keys are available
+ */
+static int kbd_tstc(void)
+{
+	/* Just get input to do this for us */
+	return config.inited ? input_tstc(&config.input) : 0;
+}
+
+/**
+ * Read a key
+ *
+ * @return ASCII key code, or 0 if no key, or -1 if error
+ */
+static int kbd_getc(void)
+{
+	/* Just get input to do this for us */
+	return config.inited ? input_getc(&config.input) : 0;
+}
+
+/**
+ * Check the keyboard, and send any keys that are pressed.
+ *
+ * This is called by input_tstc() and input_getc() when they need more
+ * characters
+ *
+ * @param input		Input configuration
+ * @return 1, to indicate that we have something to look at
+ */
+int cros_ec_kbc_check(struct input_config *input)
+{
+	static struct key_matrix_key last_keys[KBC_MAX_KEYS];
+	static int last_num_keys;
+	struct key_matrix_key keys[KBC_MAX_KEYS];
+	int keycodes[KBC_MAX_KEYS];
+	int num_keys, num_keycodes;
+	int irq_pending, sent;
+
+	/*
+	 * Loop until the EC has no more keyscan records, or we have
+	 * received at least one character. This means we know that tstc()
+	 * will always return non-zero if keys have been pressed.
+	 *
+	 * Without this loop, a key release (which generates no new ascii
+	 * characters) will cause us to exit this function, and just tstc()
+	 * may return 0 before all keys have been read from the EC.
+	 */
+	do {
+		irq_pending = cros_ec_interrupt_pending(config.dev);
+		if (irq_pending) {
+			num_keys = check_for_keys(&config, keys, KBC_MAX_KEYS);
+			last_num_keys = num_keys;
+			memcpy(last_keys, keys, sizeof(keys));
+		} else {
+			/*
+			 * EC doesn't want to be asked, so use keys from last
+			 * time.
+			 */
+			num_keys = last_num_keys;
+			memcpy(keys, last_keys, sizeof(keys));
+		}
+
+		if (num_keys < 0)
+			return -1;
+		num_keycodes = key_matrix_decode(&config.matrix, keys,
+				num_keys, keycodes, KBC_MAX_KEYS);
+		sent = input_send_keycodes(input, keycodes, num_keycodes);
+	} while (irq_pending && !sent);
+
+	return 1;
+}
+
+/**
+ * Decode MBKP keyboard details from the device tree
+ *
+ * @param blob		Device tree blob
+ * @param node		Node to decode from
+ * @param config	Configuration data read from fdt
+ * @return 0 if ok, -1 on error
+ */
+static int cros_ec_keyb_decode_fdt(const void *blob, int node,
+				struct keyb *config)
+{
+	/*
+	 * Get keyboard rows and columns -@present we are limited to
+	 * 8 columns by the protocol (one byte per row scan)
+	 */
+	config->key_rows = fdtdec_get_int(blob, node, "google,key-rows", 0);
+	config->key_cols = fdtdec_get_int(blob, node, "google,key-columns", 0);
+	if (!config->key_rows || !config->key_cols ||
+			config->key_rows * config->key_cols / 8
+				> CROS_EC_KEYSCAN_COLS) {
+		debug("%s: Invalid key matrix size %d x %d\n", __func__,
+		      config->key_rows, config->key_cols);
+		return -1;
+	}
+	config->repeat_delay_ms = fdtdec_get_int(blob, node,
+						 "google,repeat-delay-ms", 0);
+	config->repeat_rate_ms = fdtdec_get_int(blob, node,
+						"google,repeat-rate-ms", 0);
+	config->ghost_filter = fdtdec_get_bool(blob, node,
+					       "google,ghost-filter");
+	return 0;
+}
+
+/**
+ * Set up the keyboard. This is called by the stdio device handler.
+ *
+ * We want to do this init when the keyboard is actually used rather than
+ * at start-up, since keyboard input may not currently be selected.
+ *
+ * @return 0 if ok, -1 on error
+ */
+static int cros_ec_init_keyboard(void)
+{
+	const void *blob = gd->fdt_blob;
+	int node;
+
+	config.dev = board_get_cros_ec_dev();
+	if (!config.dev) {
+		debug("%s: no cros_ec device: cannot init keyboard\n",
+		      __func__);
+		return -1;
+	}
+	node = fdtdec_next_compatible(blob, 0, COMPAT_GOOGLE_CROS_EC_KEYB);
+	if (node < 0) {
+		debug("%s: Node not found\n", __func__);
+		return -1;
+	}
+	if (cros_ec_keyb_decode_fdt(blob, node, &config))
+		return -1;
+	input_set_delays(&config.input, config.repeat_delay_ms,
+			 config.repeat_rate_ms);
+	if (key_matrix_init(&config.matrix, config.key_rows,
+			config.key_cols, config.ghost_filter)) {
+		debug("%s: cannot init key matrix\n", __func__);
+		return -1;
+	}
+	if (key_matrix_decode_fdt(&config.matrix, gd->fdt_blob, node)) {
+		debug("%s: Could not decode key matrix from fdt\n", __func__);
+		return -1;
+	}
+	config.inited = 1;
+	debug("%s: Matrix keyboard %dx%d ready\n", __func__, config.key_rows,
+	      config.key_cols);
+
+	return 0;
+}
+
+int drv_keyboard_init(void)
+{
+	struct stdio_dev dev;
+
+	if (input_init(&config.input, 0)) {
+		debug("%s: Cannot set up input\n", __func__);
+		return -1;
+	}
+	config.input.read_keys = cros_ec_kbc_check;
+
+	memset(&dev, '\0', sizeof(dev));
+	strcpy(dev.name, "cros-ec-keyb");
+	dev.flags = DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
+	dev.getc = kbd_getc;
+	dev.tstc = kbd_tstc;
+	dev.start = cros_ec_init_keyboard;
+
+	/* Register the device. cros_ec_init_keyboard() will be called soon */
+	return input_stdio_register(&dev);
+}
diff --git a/include/fdtdec.h b/include/fdtdec.h
index 0f4bbaa..0eaabe1 100644
--- a/include/fdtdec.h
+++ b/include/fdtdec.h
@@ -79,6 +79,7 @@ enum fdt_compat_id {
 	COMPAT_WOLFSON_WM8994_CODEC,	/* Wolfson WM8994 Sound Codec */
 	COMPAT_SAMSUNG_EXYNOS_SPI,	/* Exynos SPI */
 	COMPAT_GOOGLE_CROS_EC,		/* Google CROS_EC Protocol */
+	COMPAT_GOOGLE_CROS_EC_KEYB,	/* Google CROS_EC Keyboard */
 	COMPAT_SAMSUNG_EXYNOS_EHCI,	/* Exynos EHCI controller */
 	COMPAT_SAMSUNG_EXYNOS_USB_PHY,	/* Exynos phy controller for usb2.0 */
 	COMPAT_MAXIM_MAX77686_PMIC,	/* MAX77686 PMIC */
diff --git a/lib/fdtdec.c b/lib/fdtdec.c
index 24cd6f9..df60bee 100644
--- a/lib/fdtdec.c
+++ b/lib/fdtdec.c
@@ -54,6 +54,7 @@ static const char * const compat_names[COMPAT_COUNT] = {
 	COMPAT(WOLFSON_WM8994_CODEC, "wolfson,wm8994-codec"),
 	COMPAT(SAMSUNG_EXYNOS_SPI, "samsung,exynos-spi"),
 	COMPAT(GOOGLE_CROS_EC, "google,cros-ec"),
+	COMPAT(GOOGLE_CROS_EC_KEYB, "google,cros-ec-keyb"),
 	COMPAT(SAMSUNG_EXYNOS_EHCI, "samsung,exynos-ehci"),
 	COMPAT(SAMSUNG_EXYNOS_USB_PHY, "samsung,exynos-usb-phy"),
 	COMPAT(MAXIM_MAX77686_PMIC, "maxim,max77686_pmic"),
-- 
1.8.1.3

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [U-Boot] [PATCH v4 6/7] cros: exynos: add cros-ec device nodes to exynos5250-snow.dts
  2013-04-02 10:01 [U-Boot] [PATCH v4 0/7] Add cros-ec protocol driver and enable it in smdk5250 Hung-ying Tyan
                   ` (4 preceding siblings ...)
  2013-04-02 10:01 ` [U-Boot] [PATCH v4 5/7] cros: adds cros_ec keyboard driver Hung-ying Tyan
@ 2013-04-02 10:01 ` Hung-ying Tyan
  2013-04-04 20:16   ` Simon Glass
  2013-04-02 10:01 ` [U-Boot] [PATCH v4 7/7] cros: enable cros-ec for smdk5250 Hung-ying Tyan
                   ` (2 subsequent siblings)
  8 siblings, 1 reply; 18+ messages in thread
From: Hung-ying Tyan @ 2013-04-02 10:01 UTC (permalink / raw)
  To: u-boot

This patch adds cros-ec related device nodes to exynos5250-snow.dts.
It also adds a gpio node to exynos5250.dtsi.

Signed-off-by: Hung-ying Tyan <tyanh@chromium.org>

---
Changes in v4:
- Added commit message.

Changes in v3: None
Changes in v2:
- Added gpio node to exynos5250.dtsi.
- Dropped the period from commit subject.

 arch/arm/dts/exynos5250.dtsi          |  3 ++
 board/samsung/dts/exynos5250-snow.dts | 82 +++++++++++++++++++++++++++++++++++
 2 files changed, 85 insertions(+)

diff --git a/arch/arm/dts/exynos5250.dtsi b/arch/arm/dts/exynos5250.dtsi
index 6c08eb7..2644131 100644
--- a/arch/arm/dts/exynos5250.dtsi
+++ b/arch/arm/dts/exynos5250.dtsi
@@ -182,4 +182,7 @@
 		reg = <0x12230000 0x1000>;
 		interrupts = <0 78 0>;
 	};
+
+	gpio: gpio {
+	};
 };
diff --git a/board/samsung/dts/exynos5250-snow.dts b/board/samsung/dts/exynos5250-snow.dts
index af788a6..a7526e5 100644
--- a/board/samsung/dts/exynos5250-snow.dts
+++ b/board/samsung/dts/exynos5250-snow.dts
@@ -43,6 +43,33 @@
 		};
 	};
 
+	i2c4: i2c at 12ca0000 {
+		cros-ec at 1e {
+			reg = <0x1e>;
+			compatible = "google,cros-ec";
+			i2c-max-frequency = <100000>;
+			ec-interrupt = <&gpio 174 1>;
+		};
+
+		power-regulator at 48 {
+			compatible = "ti,tps65090";
+			reg = <0x48>;
+		};
+	};
+
+	spi at 131b0000 {
+		spi-max-frequency = <1000000>;
+		spi-deactivate-delay = <100>;
+		cros-ec at 0 {
+			reg = <0>;
+			compatible = "google,cros-ec";
+			spi-max-frequency = <5000000>;
+			ec-interrupt = <&gpio 174 1>;
+			optimise-flash-write;
+			status = "disabled";
+		};
+	};
+
 	sound at 12d60000 {
 		samsung,i2s-epll-clock-frequency = <192000000>;
 		samsung,i2s-sampling-rate = <48000>;
@@ -66,4 +93,59 @@
 			compatible = "maxim,max77686_pmic";
 		};
 	};
+
+	cros-ec-keyb {
+		compatible = "google,cros-ec-keyb";
+		google,key-rows = <8>;
+		google,key-columns = <13>;
+		google,repeat-delay-ms = <240>;
+		google,repeat-rate-ms = <30>;
+		google,ghost-filter;
+		/*
+		 * Keymap entries take the form of 0xRRCCKKKK where
+		 * RR=Row CC=Column KKKK=Key Code
+		 * The values below are for a US keyboard layout and
+		 * are taken from the Linux driver. Note that the
+		 * 102ND key is not used for US keyboards.
+		 */
+		linux,keymap = <
+			/* CAPSLCK F1         B          F10     */
+			0x0001003a 0x0002003b 0x00030030 0x00040044
+			/* N       =          R_ALT      ESC     */
+			0x00060031 0x0008000d 0x000a0064 0x01010001
+			/* F4      G          F7         H       */
+			0x0102003e 0x01030022 0x01040041 0x01060023
+			/* '       F9         BKSPACE    L_CTRL  */
+			0x01080028 0x01090043 0x010b000e 0x0200001d
+			/* TAB     F3         T          F6      */
+			0x0201000f 0x0202003d 0x02030014 0x02040040
+			/* ]       Y          102ND      [       */
+			0x0205001b 0x02060015 0x02070056 0x0208001a
+			/* F8      GRAVE      F2         5       */
+			0x02090042 0x03010029 0x0302003c 0x03030006
+			/* F5      6          -          \       */
+			0x0304003f 0x03060007 0x0308000c 0x030b002b
+			/* R_CTRL  A          D          F       */
+			0x04000061 0x0401001e 0x04020020 0x04030021
+			/* S       K          J          ;       */
+			0x0404001f 0x04050025 0x04060024 0x04080027
+			/* L       ENTER      Z          C       */
+			0x04090026 0x040b001c 0x0501002c 0x0502002e
+			/* V       X          ,          M       */
+			0x0503002f 0x0504002d 0x05050033 0x05060032
+			/* L_SHIFT /          .          SPACE   */
+			0x0507002a 0x05080035 0x05090034 0x050B0039
+			/* 1       3          4          2       */
+			0x06010002 0x06020004 0x06030005 0x06040003
+			/* 8       7          0          9       */
+			0x06050009 0x06060008 0x0608000b 0x0609000a
+			/* L_ALT   DOWN       RIGHT      Q       */
+			0x060a0038 0x060b006c 0x060c006a 0x07010010
+			/* E       R          W          I       */
+			0x07020012 0x07030013 0x07040011 0x07050017
+			/* U       R_SHIFT    P          O       */
+			0x07060016 0x07070036 0x07080019 0x07090018
+			/* UP      LEFT    */
+			0x070b0067 0x070c0069>;
+	};
 };
-- 
1.8.1.3

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [U-Boot] [PATCH v4 7/7] cros: enable cros-ec for smdk5250
  2013-04-02 10:01 [U-Boot] [PATCH v4 0/7] Add cros-ec protocol driver and enable it in smdk5250 Hung-ying Tyan
                   ` (5 preceding siblings ...)
  2013-04-02 10:01 ` [U-Boot] [PATCH v4 6/7] cros: exynos: add cros-ec device nodes to exynos5250-snow.dts Hung-ying Tyan
@ 2013-04-02 10:01 ` Hung-ying Tyan
  2013-04-04 20:17   ` Simon Glass
  2013-04-04 20:18 ` [U-Boot] [PATCH v4 0/7] Add cros-ec protocol driver and enable it in smdk5250 Simon Glass
  2013-04-30 16:07 ` Tom Rini
  8 siblings, 1 reply; 18+ messages in thread
From: Hung-ying Tyan @ 2013-04-02 10:01 UTC (permalink / raw)
  To: u-boot

This patch initiates cros-ec in board_init() to enable it for smdk5250.

Signed-off-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Vincent Palatin <vpalatin@chromium.org>
Signed-off-by: Hung-ying Tyan <tyanh@chromium.org>
---
Changes in v4: None
Changes in v3: None
Changes in v2:
- Moved code from smdk5250.c (non-FDT) to exynos5-dt.c (FDT).
- Moved code from smdk5250.h to exynos5250-dt.h.
- Added commit message.
- Dropped the period from commit subject.

 board/samsung/smdk5250/exynos5-dt.c | 45 +++++++++++++++++++++++++++++++++++++
 include/configs/exynos5250-dt.h     | 10 ++++++++-
 2 files changed, 54 insertions(+), 1 deletion(-)

diff --git a/board/samsung/smdk5250/exynos5-dt.c b/board/samsung/smdk5250/exynos5-dt.c
index b01fe72..8be3192 100644
--- a/board/samsung/smdk5250/exynos5-dt.c
+++ b/board/samsung/smdk5250/exynos5-dt.c
@@ -21,6 +21,7 @@
  */
 
 #include <common.h>
+#include <cros_ec.h>
 #include <fdtdec.h>
 #include <asm/io.h>
 #include <errno.h>
@@ -39,6 +40,13 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
+struct local_info {
+	struct cros_ec_dev *cros_ec_dev;	/* Pointer to cros_ec device */
+	int cros_ec_err;			/* Error for cros_ec, 0 if ok */
+};
+
+static struct local_info local;
+
 #ifdef CONFIG_USB_EHCI_EXYNOS
 int board_usb_vbus_init(void)
 {
@@ -55,12 +63,30 @@ int board_usb_vbus_init(void)
 }
 #endif
 
+struct cros_ec_dev *board_get_cros_ec_dev(void)
+{
+	return local.cros_ec_dev;
+}
+
+static int board_init_cros_ec_devices(const void *blob)
+{
+	local.cros_ec_err = cros_ec_init(blob, &local.cros_ec_dev);
+	if (local.cros_ec_err)
+		return -1;  /* Will report in board_late_init() */
+
+	return 0;
+}
+
 int board_init(void)
 {
 	gd->bd->bi_boot_params = (PHYS_SDRAM_1 + 0x100UL);
 #ifdef CONFIG_EXYNOS_SPI
 	spi_init();
 #endif
+
+	if (board_init_cros_ec_devices(gd->fdt_blob))
+		return -1;
+
 #ifdef CONFIG_USB_EHCI_EXYNOS
 	board_usb_vbus_init();
 #endif
@@ -337,3 +363,22 @@ int board_early_init_f(void)
 	return err;
 }
 #endif
+
+#ifdef CONFIG_BOARD_LATE_INIT
+int board_late_init(void)
+{
+	stdio_print_current_devices();
+
+	if (local.cros_ec_err) {
+		/* Force console on */
+		gd->flags &= ~GD_FLG_SILENT;
+
+		printf("cros-ec communications failure %d\n",
+		       local.cros_ec_err);
+		puts("\nPlease reset with Power+Refresh\n\n");
+		panic("Cannot init cros-ec device");
+		return -1;
+	}
+	return 0;
+}
+#endif
diff --git a/include/configs/exynos5250-dt.h b/include/configs/exynos5250-dt.h
index 0721c17..80dfce7 100644
--- a/include/configs/exynos5250-dt.h
+++ b/include/configs/exynos5250-dt.h
@@ -77,11 +77,19 @@
 #define CONFIG_BAUDRATE			115200
 #define EXYNOS5_DEFAULT_UART_OFFSET	0x010000
 
+/* Enable keyboard */
+#define CONFIG_CROS_EC		/* CROS_EC protocol */
+#define CONFIG_CROS_EC_SPI		/* Support CROS_EC over SPI */
+#define CONFIG_CROS_EC_I2C		/* Support CROS_EC over I2C */
+#define CONFIG_CROS_EC_KEYB	/* CROS_EC keyboard input */
+#define CONFIG_CMD_CROS_EC
+#define CONFIG_KEYBOARD
+
 /* Console configuration */
 #define CONFIG_CONSOLE_MUX
 #define CONFIG_SYS_CONSOLE_IS_IN_ENV
 #define EXYNOS_DEVICE_SETTINGS \
-		"stdin=serial\0" \
+		"stdin=serial,cros-ec-keyb\0" \
 		"stdout=serial,lcd\0" \
 		"stderr=serial,lcd\0"
 
-- 
1.8.1.3

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [U-Boot] [PATCH v4 1/7] cros: add cros_ec driver
  2013-04-02 10:01 ` [U-Boot] [PATCH v4 1/7] cros: add cros_ec driver Hung-ying Tyan
@ 2013-04-04 20:13   ` Simon Glass
  0 siblings, 0 replies; 18+ messages in thread
From: Simon Glass @ 2013-04-04 20:13 UTC (permalink / raw)
  To: u-boot

On Tue, Apr 2, 2013 at 3:01 AM, Hung-ying Tyan <tyanh@chromium.org> wrote:

> This patch adds the cros_ec driver that implements the protocol for
> communicating with Google's ChromeOS embedded controller.
>
> Signed-off-by: Bernie Thompson <bhthompson@chromium.org>
> Signed-off-by: Bill Richardson <wfrichar@chromium.org>
> Signed-off-by: Che-Liang Chiou <clchiou@chromium.org>
> Signed-off-by: Doug Anderson <dianders@chromium.org>
> Signed-off-by: Gabe Black <gabeblack@chromium.org>
> Signed-off-by: Hung-ying Tyan <tyanh@chromium.org>
> Signed-off-by: Louis Yung-Chieh Lo <yjlou@chromium.org>
> Signed-off-by: Randall Spangler <rspangler@chromium.org>
> Signed-off-by: Sean Paul <seanpaul@chromium.org>
> Signed-off-by: Simon Glass <sjg@chromium.org>
> Signed-off-by: Vincent Palatin <vpalatin@chromium.org>
>

Acked-by: Simon Glass <sjg@chromium.org>

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [U-Boot] [PATCH v4 2/7] cros: add I2C support for cros_ec
  2013-04-02 10:01 ` [U-Boot] [PATCH v4 2/7] cros: add I2C support for cros_ec Hung-ying Tyan
@ 2013-04-04 20:14   ` Simon Glass
  0 siblings, 0 replies; 18+ messages in thread
From: Simon Glass @ 2013-04-04 20:14 UTC (permalink / raw)
  To: u-boot

On Tue, Apr 2, 2013 at 3:01 AM, Hung-ying Tyan <tyanh@chromium.org> wrote:

> This patch adds I2C support for carrying out the cros_ec protocol.
>
> Signed-off-by: Randall Spangler <rspangler@chromium.org>
> Signed-off-by: Simon Glass <sjg@chromium.org>
> Signed-off-by: Hung-ying Tyan <tyanh@chromium.org>
>
> ---
> Changes in v4: None
> 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.
>

Acked-by: Simon Glass <sjg@chromium.org>

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [U-Boot] [PATCH v4 3/7] cros: add SPI support for cros_ec
  2013-04-02 10:01 ` [U-Boot] [PATCH v4 3/7] cros: add SPI " Hung-ying Tyan
@ 2013-04-04 20:14   ` Simon Glass
  0 siblings, 0 replies; 18+ messages in thread
From: Simon Glass @ 2013-04-04 20:14 UTC (permalink / raw)
  To: u-boot

On Tue, Apr 2, 2013 at 3:01 AM, Hung-ying Tyan <tyanh@chromium.org> wrote:

> This patch adds SPI support for carrying out the cros_ec protocol.
>
> Signed-off-by: Hung-ying Tyan <tyanh@chromium.org>
> Signed-off-by: Randall Spangler <rspangler@chromium.org>
> Signed-off-by: Simon Glass <sjg@chromium.org>
>

Acked-by: Simon Glass <sjg@chromium.org>

>
> ---
> 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
>
>

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [U-Boot] [PATCH v4 4/7] cros: add LPC support for cros_ec
  2013-04-02 10:01 ` [U-Boot] [PATCH v4 4/7] cros: add LPC " Hung-ying Tyan
@ 2013-04-04 20:15   ` Simon Glass
  0 siblings, 0 replies; 18+ messages in thread
From: Simon Glass @ 2013-04-04 20:15 UTC (permalink / raw)
  To: u-boot

On Tue, Apr 2, 2013 at 3:01 AM, Hung-ying Tyan <tyanh@chromium.org> wrote:

> This patch adds LPC support for carrying out the cros_ec protocol.
>
> Signed-off-by: Randall Spangler <rspangler@chromium.org>
> Signed-off-by: Simon Glass <sjg@chromium.org>
> Signed-off-by: Hung-ying Tyan <tyanh@chromium.org>
>
> ---
> Changes in v4: None
> 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_lpc.c | 283
> +++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 284 insertions(+)
>  create mode 100644 drivers/misc/cros_ec_lpc.c
>

Acked-by: Simon Glass <sjg@chromium.org>

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [U-Boot] [PATCH v4 5/7] cros: adds cros_ec keyboard driver
  2013-04-02 10:01 ` [U-Boot] [PATCH v4 5/7] cros: adds cros_ec keyboard driver Hung-ying Tyan
@ 2013-04-04 20:15   ` Simon Glass
  0 siblings, 0 replies; 18+ messages in thread
From: Simon Glass @ 2013-04-04 20:15 UTC (permalink / raw)
  To: u-boot

On Tue, Apr 2, 2013 at 3:01 AM, Hung-ying Tyan <tyanh@chromium.org> wrote:

> This patch adds the driver for keyboard that's controlled by ChromeOS EC.
>
> Signed-off-by: Randall Spangler <rspangler@chromium.org>
> Signed-off-by: Simon Glass <sjg@chromium.org>
> Signed-off-by: Vincent Palatin <vpalatin@chromium.org>
> Signed-off-by: Hung-ying Tyan <tyanh@chromium.org>
>
> ---
> Changes in v4:
> - Added cros-ec-keyb.txt.
>

Acked-by: Simon Glass <sjg@chromium.org>

>
> Changes in v3:
> - Rearranged #include directives in alphabetical order.
> - Removed outdated TODO and irrelevant bug reference in comments.
>
> Changes in v2:
> - Fixed warnings of exceeding 80 chars in a line.
> - Added commit message.
> - Dropped the period from commit subject.
>
>  README                                          |   5 +
>  doc/device-tree-bindings/input/cros-ec-keyb.txt |  79 +++++++
>  drivers/input/Makefile                          |   1 +
>  drivers/input/cros_ec_keyb.c                    | 261
> ++++++++++++++++++++++++
>  include/fdtdec.h                                |   1 +
>  lib/fdtdec.c                                    |   1 +
>  6 files changed, 348 insertions(+)
>  create mode 100644 doc/device-tree-bindings/input/cros-ec-keyb.txt
>  create mode 100644 drivers/input/cros_ec_keyb.c
>
>

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [U-Boot] [PATCH v4 6/7] cros: exynos: add cros-ec device nodes to exynos5250-snow.dts
  2013-04-02 10:01 ` [U-Boot] [PATCH v4 6/7] cros: exynos: add cros-ec device nodes to exynos5250-snow.dts Hung-ying Tyan
@ 2013-04-04 20:16   ` Simon Glass
  0 siblings, 0 replies; 18+ messages in thread
From: Simon Glass @ 2013-04-04 20:16 UTC (permalink / raw)
  To: u-boot

On Tue, Apr 2, 2013 at 3:01 AM, Hung-ying Tyan <tyanh@chromium.org> wrote:

> This patch adds cros-ec related device nodes to exynos5250-snow.dts.
> It also adds a gpio node to exynos5250.dtsi.
>
> Signed-off-by: Hung-ying Tyan <tyanh@chromium.org>
>
> ---
> Changes in v4:
> - Added commit message.
>
> Changes in v3: None
> Changes in v2:
> - Added gpio node to exynos5250.dtsi.
> - Dropped the period from commit subject.
>
>  arch/arm/dts/exynos5250.dtsi          |  3 ++
>  board/samsung/dts/exynos5250-snow.dts | 82
> +++++++++++++++++++++++++++++++++++
>  2 files changed, 85 insertions(+)
>

Acked-by: Simon Glass <sjg@chromium.org>

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [U-Boot] [PATCH v4 7/7] cros: enable cros-ec for smdk5250
  2013-04-02 10:01 ` [U-Boot] [PATCH v4 7/7] cros: enable cros-ec for smdk5250 Hung-ying Tyan
@ 2013-04-04 20:17   ` Simon Glass
  2013-04-16 20:42     ` Simon Glass
  0 siblings, 1 reply; 18+ messages in thread
From: Simon Glass @ 2013-04-04 20:17 UTC (permalink / raw)
  To: u-boot

On Tue, Apr 2, 2013 at 3:01 AM, Hung-ying Tyan <tyanh@chromium.org> wrote:

> This patch initiates cros-ec in board_init() to enable it for smdk5250.
>
> Signed-off-by: Simon Glass <sjg@chromium.org>
> Signed-off-by: Vincent Palatin <vpalatin@chromium.org>
> Signed-off-by: Hung-ying Tyan <tyanh@chromium.org>
> ---
> Changes in v4: None
> Changes in v3: None
> Changes in v2:
> - Moved code from smdk5250.c (non-FDT) to exynos5-dt.c (FDT).
> - Moved code from smdk5250.h to exynos5250-dt.h.
> - Added commit message.
> - Dropped the period from commit subject.
>

Acked-by: Simon Glass <sjg@chromium.org>

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [U-Boot] [PATCH v4 0/7] Add cros-ec protocol driver and enable it in smdk5250
  2013-04-02 10:01 [U-Boot] [PATCH v4 0/7] Add cros-ec protocol driver and enable it in smdk5250 Hung-ying Tyan
                   ` (6 preceding siblings ...)
  2013-04-02 10:01 ` [U-Boot] [PATCH v4 7/7] cros: enable cros-ec for smdk5250 Hung-ying Tyan
@ 2013-04-04 20:18 ` Simon Glass
  2013-04-30 16:07 ` Tom Rini
  8 siblings, 0 replies; 18+ messages in thread
From: Simon Glass @ 2013-04-04 20:18 UTC (permalink / raw)
  To: u-boot

Hi Hung-ying,

On Tue, Apr 2, 2013 at 3:01 AM, Hung-ying Tyan <tyanh@chromium.org> wrote:

> This patch series adds the drivers for the cros-ec protocol that is used to
> communicate with the ChromeOS Embedded Controller (EC). The series also
> enables
> its use in Google Snow based on smdk5250.
>
> The series depends on the following patches:
> 1) http://patchwork.ozlabs.org/patch/217347 add dts file for Snow
> 2) mmc series: http://patchwork.ozlabs.org/patch/225008
> 3) power patches needed by one of the mmc patches
>    http://patchwork.ozlabs.org/patch/220060 EXYNOS5: Add function to
> setup set ps hold
>    http://patchwork.ozlabs.org/patch/220061 SMDK5250: Add PMIC voltage
> settings (needed by one of the mmc patches)
>

This seems to work fine on snow. There is a question mark around the GPIO
numbering patch which is still in progress, but that will appear when it is
ready, and is separate from this series.


> -----
>
> Changes in v4:
> - Removed unrelated exynos-spi.txt.
> - Moved cros-ec-keyb.txt to the cros-ec-keyb patch.
> - Removed old code and comment.
>
> Changes in v3:
> - Rearranged #include directives in alphabetical order.
> - Removed outdated TODO and irrelevant bug reference in comments.
>
> Changes in v2:
> - Moved code from smdk5250.c (non-FDT) to exynos5-dt.c (FDT).
> - Moved code from smdk5250.h to exynos5250-dt.h.
> - Added gpio node to exynos5250.dtsi.
> - Fixed warnings of exceeding 80 chars in a line.
> - Added commit message.
> - Dropped the period from commit subject.
>
> Hung-ying Tyan (7):
>   cros: add cros_ec driver
>   cros: add I2C support for cros_ec
>   cros: add SPI support for cros_ec
>   cros: add LPC support for cros_ec
>   cros: adds cros_ec keyboard driver
>   cros: exynos: add cros-ec device nodes to exynos5250-snow.dts
>   cros: enable cros-ec for smdk5250
>
>  README                                          |    5 +
>  arch/arm/dts/exynos5250.dtsi                    |    3 +
>  board/samsung/dts/exynos5250-snow.dts           |   82 ++
>  board/samsung/smdk5250/exynos5-dt.c             |   45 +
>  doc/device-tree-bindings/input/cros-ec-keyb.txt |   79 ++
>  doc/device-tree-bindings/misc/cros-ec.txt       |   38 +
>  drivers/input/Makefile                          |    1 +
>  drivers/input/cros_ec_keyb.c                    |  261 ++++
>  drivers/misc/Makefile                           |    4 +
>  drivers/misc/cros_ec.c                          | 1304
> ++++++++++++++++++++
>  drivers/misc/cros_ec_i2c.c                      |  199 ++++
>  drivers/misc/cros_ec_lpc.c                      |  283 +++++
>  drivers/misc/cros_ec_spi.c                      |  161 +++
>  drivers/spi/exynos_spi.c                        |   22 +
>  include/configs/exynos5250-dt.h                 |   10 +-
>  include/cros_ec.h                               |  449 +++++++
>  include/cros_ec_message.h                       |   44 +
>  include/ec_commands.h                           | 1440
> +++++++++++++++++++++++
>  include/fdtdec.h                                |    2 +
>  include/spi.h                                   |   16 +
>  lib/fdtdec.c                                    |    2 +
>  21 files changed, 4449 insertions(+), 1 deletion(-)
>  create mode 100644 doc/device-tree-bindings/input/cros-ec-keyb.txt
>  create mode 100644 doc/device-tree-bindings/misc/cros-ec.txt
>  create mode 100644 drivers/input/cros_ec_keyb.c
>  create mode 100644 drivers/misc/cros_ec.c
>  create mode 100644 drivers/misc/cros_ec_i2c.c
>  create mode 100644 drivers/misc/cros_ec_lpc.c
>  create mode 100644 drivers/misc/cros_ec_spi.c
>  create mode 100644 include/cros_ec.h
>  create mode 100644 include/cros_ec_message.h
>  create mode 100644 include/ec_commands.h
>
> --
> 1.8.1.3
>
>
Regards,
Simon

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [U-Boot] [PATCH v4 7/7] cros: enable cros-ec for smdk5250
  2013-04-04 20:17   ` Simon Glass
@ 2013-04-16 20:42     ` Simon Glass
  0 siblings, 0 replies; 18+ messages in thread
From: Simon Glass @ 2013-04-16 20:42 UTC (permalink / raw)
  To: u-boot

Hi Minkyu,

On Thu, Apr 4, 2013 at 1:17 PM, Simon Glass <sjg@chromium.org> wrote:
> On Tue, Apr 2, 2013 at 3:01 AM, Hung-ying Tyan <tyanh@chromium.org> wrote:
>>
>> This patch initiates cros-ec in board_init() to enable it for smdk5250.
>>
>> Signed-off-by: Simon Glass <sjg@chromium.org>
>> Signed-off-by: Vincent Palatin <vpalatin@chromium.org>
>> Signed-off-by: Hung-ying Tyan <tyanh@chromium.org>
>> ---
>> Changes in v4: None
>> Changes in v3: None
>> Changes in v2:
>> - Moved code from smdk5250.c (non-FDT) to exynos5-dt.c (FDT).
>> - Moved code from smdk5250.h to exynos5250-dt.h.
>> - Added commit message.
>> - Dropped the period from commit subject.
>
>
> Acked-by: Simon Glass <sjg@chromium.org>
>

I see now that this patch has the wrong tag (cros: but should be
exynos:) and so perhaps you didn't see it. It was queued up for the
current release but may be too late now - can you please take a look?

Regards,
Simon

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [U-Boot] [PATCH v4 0/7] Add cros-ec protocol driver and enable it in smdk5250
  2013-04-02 10:01 [U-Boot] [PATCH v4 0/7] Add cros-ec protocol driver and enable it in smdk5250 Hung-ying Tyan
                   ` (7 preceding siblings ...)
  2013-04-04 20:18 ` [U-Boot] [PATCH v4 0/7] Add cros-ec protocol driver and enable it in smdk5250 Simon Glass
@ 2013-04-30 16:07 ` Tom Rini
  8 siblings, 0 replies; 18+ messages in thread
From: Tom Rini @ 2013-04-30 16:07 UTC (permalink / raw)
  To: u-boot

On Tue, Apr 02, 2013 at 06:01:47PM +0800, Hung-ying Tyan wrote:

> This patch series adds the drivers for the cros-ec protocol that is used to
> communicate with the ChromeOS Embedded Controller (EC). The series also enables
> its use in Google Snow based on smdk5250.
> 
> The series depends on the following patches:
> 1) http://patchwork.ozlabs.org/patch/217347 add dts file for Snow
> 2) mmc series: http://patchwork.ozlabs.org/patch/225008
> 3) power patches needed by one of the mmc patches
>    http://patchwork.ozlabs.org/patch/220060 EXYNOS5: Add function to setup set ps hold
>    http://patchwork.ozlabs.org/patch/220061 SMDK5250: Add PMIC voltage settings (needed by one of the mmc patches)

While most of the changes to make this apply where easy, the last part
depends on board/samsung/smdk5250/exynos5-dt.c which I just don't see,
so I'm guessing is in the samsung tree?  Please do a v5 and make sure to
cc Minkyu Kang on the series, thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20130430/3cddb7b8/attachment.pgp>

^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2013-04-30 16:07 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-04-02 10:01 [U-Boot] [PATCH v4 0/7] Add cros-ec protocol driver and enable it in smdk5250 Hung-ying Tyan
2013-04-02 10:01 ` [U-Boot] [PATCH v4 1/7] cros: add cros_ec driver Hung-ying Tyan
2013-04-04 20:13   ` Simon Glass
2013-04-02 10:01 ` [U-Boot] [PATCH v4 2/7] cros: add I2C support for cros_ec Hung-ying Tyan
2013-04-04 20:14   ` Simon Glass
2013-04-02 10:01 ` [U-Boot] [PATCH v4 3/7] cros: add SPI " Hung-ying Tyan
2013-04-04 20:14   ` Simon Glass
2013-04-02 10:01 ` [U-Boot] [PATCH v4 4/7] cros: add LPC " Hung-ying Tyan
2013-04-04 20:15   ` Simon Glass
2013-04-02 10:01 ` [U-Boot] [PATCH v4 5/7] cros: adds cros_ec keyboard driver Hung-ying Tyan
2013-04-04 20:15   ` Simon Glass
2013-04-02 10:01 ` [U-Boot] [PATCH v4 6/7] cros: exynos: add cros-ec device nodes to exynos5250-snow.dts Hung-ying Tyan
2013-04-04 20:16   ` Simon Glass
2013-04-02 10:01 ` [U-Boot] [PATCH v4 7/7] cros: enable cros-ec for smdk5250 Hung-ying Tyan
2013-04-04 20:17   ` Simon Glass
2013-04-16 20:42     ` Simon Glass
2013-04-04 20:18 ` [U-Boot] [PATCH v4 0/7] Add cros-ec protocol driver and enable it in smdk5250 Simon Glass
2013-04-30 16:07 ` Tom Rini

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.