Merge tag 'tag-chrome-platform-for-v5.1' of git://git.kernel.org/pub/scm/linux/kernel...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 12 Mar 2019 16:46:32 +0000 (09:46 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 12 Mar 2019 16:46:32 +0000 (09:46 -0700)
Pull chrome platform updates from Benson Leung:

 - SPDX identifier cleanup for platform/chrome

 - Cleanup series between mfd and chrome/platform, moving cros-ec
   attributes from mfd/cros_ec_dev to sub-drivers in platform/chrome

 - Wilco EC driver

 - Maintainership change to new group repository

* tag 'tag-chrome-platform-for-v5.1' of git://git.kernel.org/pub/scm/linux/kernel/git/chrome-platform/linux:
  platform/chrome: fix wilco-ec dependencies
  platform/chrome: wilco_ec: Add RTC driver
  platform/chrome: wilco_ec: Add support for raw commands in debugfs
  platform/chrome: Add new driver for Wilco EC
  platform/chrome: cros_ec: Remove cros_ec dependency in lpc_mec
  MAINTAINERS: chrome-platform: change the git tree to a chrome-platform group git tree
  platform/chrome: cros_ec_sysfs: remove pr_fmt() define
  platform/chrome: cros_ec_lightbar: remove pr_fmt() define
  platform/chrome: cros_kbd_led_backlight: switch to SPDX identifier
  platform/chrome: cros_ec_spi: switch to SPDX identifier
  platform/chrome: cros_ec_proto: switch to SPDX identifier
  platform/chrome: cros_ec_lpc: switch to SPDX identifier
  platform/chrome: cros_ec_i2c: switch to SPDX identifier
  platform/chrome: cros_ec_vbc: switch to SPDX identifier
  platform/chrome: cros_ec_sysfs: switch to SPDX identifier
  platform/chrome: cros_ec_lightbar: switch to SPDX identifier
  platform/chrome: cros_ec_debugfs: switch to SPDX identifier
  platform/chrome: cromeos_pstore: switch to SPDX identifier

27 files changed:
Documentation/ABI/testing/debugfs-wilco-ec [new file with mode: 0644]
MAINTAINERS
drivers/platform/chrome/Kconfig
drivers/platform/chrome/Makefile
drivers/platform/chrome/chromeos_pstore.c
drivers/platform/chrome/cros_ec_debugfs.c
drivers/platform/chrome/cros_ec_i2c.c
drivers/platform/chrome/cros_ec_lightbar.c
drivers/platform/chrome/cros_ec_lpc.c
drivers/platform/chrome/cros_ec_lpc_mec.c
drivers/platform/chrome/cros_ec_lpc_mec.h
drivers/platform/chrome/cros_ec_lpc_reg.c
drivers/platform/chrome/cros_ec_lpc_reg.h
drivers/platform/chrome/cros_ec_proto.c
drivers/platform/chrome/cros_ec_spi.c
drivers/platform/chrome/cros_ec_sysfs.c
drivers/platform/chrome/cros_ec_vbc.c
drivers/platform/chrome/cros_kbd_led_backlight.c
drivers/platform/chrome/wilco_ec/Kconfig [new file with mode: 0644]
drivers/platform/chrome/wilco_ec/Makefile [new file with mode: 0644]
drivers/platform/chrome/wilco_ec/core.c [new file with mode: 0644]
drivers/platform/chrome/wilco_ec/debugfs.c [new file with mode: 0644]
drivers/platform/chrome/wilco_ec/mailbox.c [new file with mode: 0644]
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/rtc-wilco-ec.c [new file with mode: 0644]
include/linux/platform_data/wilco-ec.h [new file with mode: 0644]

diff --git a/Documentation/ABI/testing/debugfs-wilco-ec b/Documentation/ABI/testing/debugfs-wilco-ec
new file mode 100644 (file)
index 0000000..f814f11
--- /dev/null
@@ -0,0 +1,23 @@
+What:          /sys/kernel/debug/wilco_ec/raw
+Date:          January 2019
+KernelVersion: 5.1
+Description:
+               Write and read raw mailbox commands to the EC.
+
+               For writing:
+               Bytes 0-1 indicate the message type:
+                       00 F0 = Execute Legacy Command
+                       00 F2 = Read/Write NVRAM Property
+               Byte 2 provides the command code
+               Bytes 3+ consist of the data passed in the request
+
+               At least three bytes are required, for the msg type and command,
+               with additional bytes optional for additional data.
+
+               Example:
+               // Request EC info type 3 (EC firmware build date)
+               $ echo 00 f0 38 00 03 00 > raw
+               // View the result. The decoded ASCII result "12/21/18" is
+               // included after the raw hex.
+               $ cat raw
+               00 31 32 2f 32 31 2f 31 38 00 38 00 01 00 2f 00  .12/21/18.8...
index e2ec45968a1643d1a8e977caa21879fdd8d4c46a..4f004dc0a0f21ef2a9babf48e1f3e0d108df1b48 100644 (file)
@@ -3755,7 +3755,7 @@ CHROME HARDWARE PLATFORM SUPPORT
 M:     Benson Leung <bleung@chromium.org>
 M:     Enric Balletbo i Serra <enric.balletbo@collabora.com>
 S:     Maintained
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/bleung/chrome-platform.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/chrome-platform/linux.git
 F:     drivers/platform/chrome/
 
 CHROMEOS EC SUBDRIVERS
index 5e2fde5ff63d78d9f1c3a6a7aea57f502b21c949..9186d81a51cc1347b0c733a5caa2622088d10ccf 100644 (file)
@@ -152,4 +152,6 @@ config CROS_EC_SYSFS
          To compile this driver as a module, choose M here: the
          module will be called cros_ec_sysfs.
 
+source "drivers/platform/chrome/wilco_ec/Kconfig"
+
 endif # CHROMEOS_PLATFORMS
index fdbee501931b10eea96d1619e5bbe6ed8e724a49..1e2f0029b5971f2a045814e9b5193eba3e25938e 100644 (file)
@@ -14,3 +14,5 @@ obj-$(CONFIG_CROS_EC_LIGHTBAR)                += cros_ec_lightbar.o
 obj-$(CONFIG_CROS_EC_VBC)              += cros_ec_vbc.o
 obj-$(CONFIG_CROS_EC_DEBUGFS)          += cros_ec_debugfs.o
 obj-$(CONFIG_CROS_EC_SYSFS)            += cros_ec_sysfs.o
+
+obj-$(CONFIG_WILCO_EC)                 += wilco_ec/
index b0693fdec8c6a700acdfdc1f704bea97c3abfd68..d13770785fb5ea1215558f12bdbfacab916dc5ca 100644 (file)
@@ -1,12 +1,7 @@
-/*
- *  chromeos_pstore.c - Driver to instantiate Chromebook ramoops device
- *
- *  Copyright (C) 2013 Google, Inc.
- *
- *  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, version 2 of the License.
- */
+// SPDX-License-Identifier: GPL-2.0
+// Driver to instantiate Chromebook ramoops device.
+//
+// Copyright (C) 2013 Google, Inc.
 
 #include <linux/acpi.h>
 #include <linux/dmi.h>
@@ -138,5 +133,5 @@ static void __exit chromeos_pstore_exit(void)
 module_init(chromeos_pstore_init);
 module_exit(chromeos_pstore_exit);
 
-MODULE_DESCRIPTION("Chrome OS pstore module");
-MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("ChromeOS pstore module");
+MODULE_LICENSE("GPL v2");
index 6cacac53dfce36b559e955b4f9a34a7d82182ab2..900c7073c46f4e4ca530463fcfa91e79b38b10b4 100644 (file)
@@ -1,21 +1,7 @@
-/*
- * cros_ec_debugfs - debug logs for Chrome OS EC
- *
- * Copyright 2015 Google, Inc.
- *
- * 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, see <http://www.gnu.org/licenses/>.
- */
+// SPDX-License-Identifier: GPL-2.0+
+// Debug logs for the ChromeOS EC
+//
+// Copyright (C) 2015 Google, Inc.
 
 #include <linux/circ_buf.h>
 #include <linux/debugfs.h>
index 9a009eaa4adabe5df3231d8c5974ddfe3f25faf6..61d75395f86d802c3ad9638e2520bcee863b2440 100644 (file)
@@ -1,17 +1,7 @@
-/*
- * ChromeOS EC multi-function device (I2C)
- *
- * Copyright (C) 2012 Google, Inc
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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.
- */
+// SPDX-License-Identifier: GPL-2.0
+// I2C interface for ChromeOS Embedded Controller
+//
+// Copyright (C) 2012 Google, Inc
 
 #include <linux/acpi.h>
 #include <linux/delay.h>
@@ -372,5 +362,5 @@ static struct i2c_driver cros_ec_driver = {
 
 module_i2c_driver(cros_ec_driver);
 
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("ChromeOS EC multi function device");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("I2C interface for ChromeOS Embedded Controller");
index c3e4e6e5211d6eb6ca02e9669bd40121df3a8498..d30a6650b0b5591c6a691d303da86af2aa7ef4f0 100644 (file)
@@ -1,23 +1,7 @@
-/*
- * cros_ec_lightbar - expose the Chromebook Pixel lightbar to userspace
- *
- * Copyright (C) 2014 Google, Inc.
- *
- * 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, see <http://www.gnu.org/licenses/>.
- */
-
-#define pr_fmt(fmt) "cros_ec_lightbar: " fmt
+// SPDX-License-Identifier: GPL-2.0+
+// Expose the Chromebook Pixel lightbar to userspace
+//
+// Copyright (C) 2014 Google, Inc.
 
 #include <linux/ctype.h>
 #include <linux/delay.h>
index 14684a56e40fb152705cf2ddd20dc92149f74396..c9c240fbe7c63c083356f00eb56982923388ae87 100644 (file)
@@ -1,25 +1,15 @@
-/*
- * cros_ec_lpc - LPC access to the Chrome OS Embedded Controller
- *
- * Copyright (C) 2012-2015 Google, Inc
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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.
- *
- * This driver uses the Chrome OS EC byte-level message-based protocol for
- * communicating the keyboard state (which keys are pressed) from a keyboard EC
- * to the AP over some bus (such as i2c, lpc, spi).  The EC does debouncing,
- * but everything else (including deghosting) is done here.  The main
- * motivation for this is to keep the EC firmware as simple as possible, since
- * it cannot be easily upgraded and EC flash/IRAM space is relatively
- * expensive.
- */
+// SPDX-License-Identifier: GPL-2.0
+// LPC interface for ChromeOS Embedded Controller
+//
+// Copyright (C) 2012-2015 Google, Inc
+//
+// This driver uses the ChromeOS EC byte-level message-based protocol for
+// communicating the keyboard state (which keys are pressed) from a keyboard EC
+// to the AP over some bus (such as i2c, lpc, spi).  The EC does debouncing,
+// but everything else (including deghosting) is done here.  The main
+// motivation for this is to keep the EC firmware as simple as possible, since
+// it cannot be easily upgraded and EC flash/IRAM space is relatively
+// expensive.
 
 #include <linux/acpi.h>
 #include <linux/dmi.h>
index c4edfa83e493062fcd65363e4733387562211ef5..d8890bafb55d2a3f01ad4e96b991cf382d2678b7 100644 (file)
@@ -1,29 +1,10 @@
-/*
- * cros_ec_lpc_mec - LPC variant I/O for Microchip EC
- *
- * Copyright (C) 2016 Google, Inc
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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.
- *
- * This driver uses the Chrome OS EC byte-level message-based protocol for
- * communicating the keyboard state (which keys are pressed) from a keyboard EC
- * to the AP over some bus (such as i2c, lpc, spi).  The EC does debouncing,
- * but everything else (including deghosting) is done here.  The main
- * motivation for this is to keep the EC firmware as simple as possible, since
- * it cannot be easily upgraded and EC flash/IRAM space is relatively
- * expensive.
- */
+// SPDX-License-Identifier: GPL-2.0
+// LPC variant I/O for Microchip EC
+//
+// Copyright (C) 2016 Google, Inc
 
 #include <linux/delay.h>
 #include <linux/io.h>
-#include <linux/mfd/cros_ec_commands.h>
 #include <linux/mutex.h>
 #include <linux/types.h>
 
@@ -34,6 +15,7 @@
  * EC mutex because memmap data may be accessed without it being held.
  */
 static struct mutex io_mutex;
+static u16 mec_emi_base, mec_emi_end;
 
 /*
  * cros_ec_lpc_mec_emi_write_address
@@ -46,10 +28,37 @@ static struct mutex io_mutex;
 static void cros_ec_lpc_mec_emi_write_address(u16 addr,
                        enum cros_ec_lpc_mec_emi_access_mode access_type)
 {
-       /* Address relative to start of EMI range */
-       addr -= MEC_EMI_RANGE_START;
-       outb((addr & 0xfc) | access_type, MEC_EMI_EC_ADDRESS_B0);
-       outb((addr >> 8) & 0x7f, MEC_EMI_EC_ADDRESS_B1);
+       outb((addr & 0xfc) | access_type, MEC_EMI_EC_ADDRESS_B0(mec_emi_base));
+       outb((addr >> 8) & 0x7f, MEC_EMI_EC_ADDRESS_B1(mec_emi_base));
+}
+
+/**
+ * cros_ec_lpc_mec_in_range() - Determine if addresses are in MEC EMI range.
+ *
+ * @offset: Address offset
+ * @length: Number of bytes to check
+ *
+ * Return: 1 if in range, 0 if not, and -EINVAL on failure
+ *         such as the mec range not being initialized
+ */
+int cros_ec_lpc_mec_in_range(unsigned int offset, unsigned int length)
+{
+       if (length == 0)
+               return -EINVAL;
+
+       if (WARN_ON(mec_emi_base == 0 || mec_emi_end == 0))
+               return -EINVAL;
+
+       if (offset >= mec_emi_base && offset < mec_emi_end) {
+               if (WARN_ON(offset + length - 1 >= mec_emi_end))
+                       return -EINVAL;
+               return 1;
+       }
+
+       if (WARN_ON(offset + length > mec_emi_base && offset < mec_emi_end))
+               return -EINVAL;
+
+       return 0;
 }
 
 /*
@@ -71,6 +80,11 @@ u8 cros_ec_lpc_io_bytes_mec(enum cros_ec_lpc_mec_io_type io_type,
        u8 sum = 0;
        enum cros_ec_lpc_mec_emi_access_mode access, new_access;
 
+       /* Return checksum of 0 if window is not initialized */
+       WARN_ON(mec_emi_base == 0 || mec_emi_end == 0);
+       if (mec_emi_base == 0 || mec_emi_end == 0)
+               return 0;
+
        /*
         * Long access cannot be used on misaligned data since reading B0 loads
         * the data register and writing B3 flushes.
@@ -86,9 +100,9 @@ u8 cros_ec_lpc_io_bytes_mec(enum cros_ec_lpc_mec_io_type io_type,
        cros_ec_lpc_mec_emi_write_address(offset, access);
 
        /* Skip bytes in case of misaligned offset */
-       io_addr = MEC_EMI_EC_DATA_B0 + (offset & 0x3);
+       io_addr = MEC_EMI_EC_DATA_B0(mec_emi_base) + (offset & 0x3);
        while (i < length) {
-               while (io_addr <= MEC_EMI_EC_DATA_B3) {
+               while (io_addr <= MEC_EMI_EC_DATA_B3(mec_emi_base)) {
                        if (io_type == MEC_IO_READ)
                                buf[i] = inb(io_addr++);
                        else
@@ -118,7 +132,7 @@ u8 cros_ec_lpc_io_bytes_mec(enum cros_ec_lpc_mec_io_type io_type,
                }
 
                /* Access [B0, B3] on each loop pass */
-               io_addr = MEC_EMI_EC_DATA_B0;
+               io_addr = MEC_EMI_EC_DATA_B0(mec_emi_base);
        }
 
 done:
@@ -128,9 +142,11 @@ done:
 }
 EXPORT_SYMBOL(cros_ec_lpc_io_bytes_mec);
 
-void cros_ec_lpc_mec_init(void)
+void cros_ec_lpc_mec_init(unsigned int base, unsigned int end)
 {
        mutex_init(&io_mutex);
+       mec_emi_base = base;
+       mec_emi_end = end;
 }
 EXPORT_SYMBOL(cros_ec_lpc_mec_init);
 
index 105068c0e9190a5a11e48e3276fe2a9da6da50c1..aa1018f6b0f24665ff1343404cf0f7437dad7ac5 100644 (file)
@@ -1,31 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
- * cros_ec_lpc_mec - LPC variant I/O for Microchip EC
+ * LPC variant I/O for Microchip EC
  *
  * Copyright (C) 2016 Google, Inc
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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.
- *
- * This driver uses the Chrome OS EC byte-level message-based protocol for
- * communicating the keyboard state (which keys are pressed) from a keyboard EC
- * to the AP over some bus (such as i2c, lpc, spi).  The EC does debouncing,
- * but everything else (including deghosting) is done here.  The main
- * motivation for this is to keep the EC firmware as simple as possible, since
- * it cannot be easily upgraded and EC flash/IRAM space is relatively
- * expensive.
  */
 
 #ifndef __CROS_EC_LPC_MEC_H
 #define __CROS_EC_LPC_MEC_H
 
-#include <linux/mfd/cros_ec_commands.h>
-
 enum cros_ec_lpc_mec_emi_access_mode {
        /* 8-bit access */
        ACCESS_TYPE_BYTE = 0x0,
@@ -45,27 +27,23 @@ enum cros_ec_lpc_mec_io_type {
        MEC_IO_WRITE,
 };
 
-/* Access IO ranges 0x800 thru 0x9ff using EMI interface instead of LPC */
-#define MEC_EMI_RANGE_START EC_HOST_CMD_REGION0
-#define MEC_EMI_RANGE_END   (EC_LPC_ADDR_MEMMAP + EC_MEMMAP_SIZE)
-
 /* EMI registers are relative to base */
-#define MEC_EMI_BASE 0x800
-#define MEC_EMI_HOST_TO_EC (MEC_EMI_BASE + 0)
-#define MEC_EMI_EC_TO_HOST (MEC_EMI_BASE + 1)
-#define MEC_EMI_EC_ADDRESS_B0 (MEC_EMI_BASE + 2)
-#define MEC_EMI_EC_ADDRESS_B1 (MEC_EMI_BASE + 3)
-#define MEC_EMI_EC_DATA_B0 (MEC_EMI_BASE + 4)
-#define MEC_EMI_EC_DATA_B1 (MEC_EMI_BASE + 5)
-#define MEC_EMI_EC_DATA_B2 (MEC_EMI_BASE + 6)
-#define MEC_EMI_EC_DATA_B3 (MEC_EMI_BASE + 7)
+#define MEC_EMI_HOST_TO_EC(MEC_EMI_BASE)       ((MEC_EMI_BASE) + 0)
+#define MEC_EMI_EC_TO_HOST(MEC_EMI_BASE)       ((MEC_EMI_BASE) + 1)
+#define MEC_EMI_EC_ADDRESS_B0(MEC_EMI_BASE)    ((MEC_EMI_BASE) + 2)
+#define MEC_EMI_EC_ADDRESS_B1(MEC_EMI_BASE)    ((MEC_EMI_BASE) + 3)
+#define MEC_EMI_EC_DATA_B0(MEC_EMI_BASE)       ((MEC_EMI_BASE) + 4)
+#define MEC_EMI_EC_DATA_B1(MEC_EMI_BASE)       ((MEC_EMI_BASE) + 5)
+#define MEC_EMI_EC_DATA_B2(MEC_EMI_BASE)       ((MEC_EMI_BASE) + 6)
+#define MEC_EMI_EC_DATA_B3(MEC_EMI_BASE)       ((MEC_EMI_BASE) + 7)
 
-/*
- * cros_ec_lpc_mec_init
+/**
+ * cros_ec_lpc_mec_init() - Initialize MEC I/O.
  *
- * Initialize MEC I/O.
+ * @base: MEC EMI Base address
+ * @end: MEC EMI End address
  */
-void cros_ec_lpc_mec_init(void);
+void cros_ec_lpc_mec_init(unsigned int base, unsigned int end);
 
 /*
  * cros_ec_lpc_mec_destroy
@@ -74,6 +52,17 @@ void cros_ec_lpc_mec_init(void);
  */
 void cros_ec_lpc_mec_destroy(void);
 
+/**
+ * cros_ec_lpc_mec_in_range() - Determine if addresses are in MEC EMI range.
+ *
+ * @offset: Address offset
+ * @length: Number of bytes to check
+ *
+ * Return: 1 if in range, 0 if not, and -EINVAL on failure
+ *         such as the mec range not being initialized
+ */
+int cros_ec_lpc_mec_in_range(unsigned int offset, unsigned int length);
+
 /**
  * cros_ec_lpc_io_bytes_mec - Read / write bytes to MEC EMI port
  *
index fc23d535c404e32c773faf0e61a854d0fa4eeaaa..0f5cd0ac8b49eb4e04171a10825920519181d7e1 100644 (file)
@@ -1,25 +1,7 @@
-/*
- * cros_ec_lpc_reg - LPC access to the Chrome OS Embedded Controller
- *
- * Copyright (C) 2016 Google, Inc
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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.
- *
- * This driver uses the Chrome OS EC byte-level message-based protocol for
- * communicating the keyboard state (which keys are pressed) from a keyboard EC
- * to the AP over some bus (such as i2c, lpc, spi).  The EC does debouncing,
- * but everything else (including deghosting) is done here.  The main
- * motivation for this is to keep the EC firmware as simple as possible, since
- * it cannot be easily upgraded and EC flash/IRAM space is relatively
- * expensive.
- */
+// SPDX-License-Identifier: GPL-2.0
+// LPC interface for ChromeOS Embedded Controller
+//
+// Copyright (C) 2016 Google, Inc
 
 #include <linux/io.h>
 #include <linux/mfd/cros_ec.h>
@@ -59,51 +41,36 @@ static u8 lpc_write_bytes(unsigned int offset, unsigned int length, u8 *msg)
 
 u8 cros_ec_lpc_read_bytes(unsigned int offset, unsigned int length, u8 *dest)
 {
-       if (length == 0)
-               return 0;
-
-       /* Access desired range through EMI interface */
-       if (offset >= MEC_EMI_RANGE_START && offset <= MEC_EMI_RANGE_END) {
-               /* Ensure we don't straddle EMI region */
-               if (WARN_ON(offset + length - 1 > MEC_EMI_RANGE_END))
-                       return 0;
+       int in_range = cros_ec_lpc_mec_in_range(offset, length);
 
-               return cros_ec_lpc_io_bytes_mec(MEC_IO_READ, offset, length,
-                                               dest);
-       }
-
-       if (WARN_ON(offset + length > MEC_EMI_RANGE_START &&
-                   offset < MEC_EMI_RANGE_START))
+       if (in_range < 0)
                return 0;
 
-       return lpc_read_bytes(offset, length, dest);
+       return in_range ?
+               cros_ec_lpc_io_bytes_mec(MEC_IO_READ,
+                                        offset - EC_HOST_CMD_REGION0,
+                                        length, dest) :
+               lpc_read_bytes(offset, length, dest);
 }
 
 u8 cros_ec_lpc_write_bytes(unsigned int offset, unsigned int length, u8 *msg)
 {
-       if (length == 0)
-               return 0;
-
-       /* Access desired range through EMI interface */
-       if (offset >= MEC_EMI_RANGE_START && offset <= MEC_EMI_RANGE_END) {
-               /* Ensure we don't straddle EMI region */
-               if (WARN_ON(offset + length - 1 > MEC_EMI_RANGE_END))
-                       return 0;
+       int in_range = cros_ec_lpc_mec_in_range(offset, length);
 
-               return cros_ec_lpc_io_bytes_mec(MEC_IO_WRITE, offset, length,
-                                               msg);
-       }
-
-       if (WARN_ON(offset + length > MEC_EMI_RANGE_START &&
-                   offset < MEC_EMI_RANGE_START))
+       if (in_range < 0)
                return 0;
 
-       return lpc_write_bytes(offset, length, msg);
+       return in_range ?
+               cros_ec_lpc_io_bytes_mec(MEC_IO_WRITE,
+                                        offset - EC_HOST_CMD_REGION0,
+                                        length, msg) :
+               lpc_write_bytes(offset, length, msg);
 }
 
 void cros_ec_lpc_reg_init(void)
 {
-       cros_ec_lpc_mec_init();
+       cros_ec_lpc_mec_init(EC_HOST_CMD_REGION0,
+                            EC_LPC_ADDR_MEMMAP + EC_MEMMAP_SIZE);
 }
 
 void cros_ec_lpc_reg_destroy(void)
index 1c12c38b306a0d490456f4af14f208d344369b5b..416fd257218299fb398c93a8173aecc96d678657 100644 (file)
@@ -1,24 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
- * cros_ec_lpc_reg - LPC access to the Chrome OS Embedded Controller
+ * LPC interface for ChromeOS Embedded Controller
  *
  * Copyright (C) 2016 Google, Inc
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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.
- *
- * This driver uses the Chrome OS EC byte-level message-based protocol for
- * communicating the keyboard state (which keys are pressed) from a keyboard EC
- * to the AP over some bus (such as i2c, lpc, spi).  The EC does debouncing,
- * but everything else (including deghosting) is done here.  The main
- * motivation for this is to keep the EC firmware as simple as possible, since
- * it cannot be easily upgraded and EC flash/IRAM space is relatively
- * expensive.
  */
 
 #ifndef __CROS_EC_LPC_REG_H
index cc7baf0ecb3c925ccda8b17138e23c3d20e2426e..97a068dff192d41541b60ad8a2e951acb42da4e8 100644 (file)
@@ -1,18 +1,7 @@
-/*
- * ChromeOS EC communication protocol helper functions
- *
- * Copyright (C) 2015 Google, Inc
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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.
- *
- */
+// SPDX-License-Identifier: GPL-2.0
+// ChromeOS EC communication protocol helper functions
+//
+// Copyright (C) 2015 Google, Inc
 
 #include <linux/mfd/cros_ec.h>
 #include <linux/delay.h>
index 6cfbc2835beba057093522815f1e3f2c0e18a956..ffc38f9d482994ff404f61ad3665241f31cbceeb 100644 (file)
@@ -1,17 +1,7 @@
-/*
- * ChromeOS EC multi-function device (SPI)
- *
- * Copyright (C) 2012 Google, Inc
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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.
- */
+// SPDX-License-Identifier: GPL-2.0
+// SPI interface for ChromeOS Embedded Controller
+//
+// Copyright (C) 2012 Google, Inc
 
 #include <linux/delay.h>
 #include <linux/kernel.h>
@@ -729,4 +719,4 @@ static struct spi_driver cros_ec_driver_spi = {
 module_spi_driver(cros_ec_driver_spi);
 
 MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("ChromeOS EC multi function device (SPI)");
+MODULE_DESCRIPTION("SPI interface for ChromeOS Embedded Controller");
index 0ff5aa30c070197396da51d5152d35c3b8360ae0..fe0b7614ae1b408647cc6d93e34cdfb0dcdc5f8f 100644 (file)
@@ -1,23 +1,7 @@
-/*
- * cros_ec_sysfs - expose the Chrome OS EC through sysfs
- *
- * Copyright (C) 2014 Google, Inc.
- *
- * 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, see <http://www.gnu.org/licenses/>.
- */
-
-#define pr_fmt(fmt) "cros_ec_sysfs: " fmt
+// SPDX-License-Identifier: GPL-2.0+
+// Expose the ChromeOS EC through sysfs
+//
+// Copyright (C) 2014 Google, Inc.
 
 #include <linux/ctype.h>
 #include <linux/delay.h>
@@ -389,5 +373,5 @@ static struct platform_driver cros_ec_sysfs_driver = {
 module_platform_driver(cros_ec_sysfs_driver);
 
 MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("ChromeOS EC control driver");
+MODULE_DESCRIPTION("Expose the ChromeOS EC through sysfs");
 MODULE_ALIAS("platform:" DRV_NAME);
index af9bfe6f385c731247a946b2fd4f18b21b8b6e63..8392a1ec33a7faec1a1fe0b013cfebacf8f8b8ba 100644 (file)
@@ -1,22 +1,8 @@
-/*
- * cros_ec_vbc - Expose the vboot context nvram to userspace
- *
- * Copyright (C) 2015 Collabora Ltd.
- *
- * based on vendor driver,
- *
- * Copyright (C) 2012 The Chromium OS Authors
- *
- * 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.
- */
+// SPDX-License-Identifier: GPL-2.0+
+// Expose the vboot context nvram to userspace
+//
+// Copyright (C) 2012 Google, Inc.
+// Copyright (C) 2015 Collabora Ltd.
 
 #include <linux/of.h>
 #include <linux/platform_device.h>
index ca3e4da852b44ac85e4c45b3fb220cab36f99715..aa409f0201fb1bedf2445b2784ed7a42f230bbf5 100644 (file)
@@ -1,18 +1,7 @@
-/*
- *  Keyboard backlight LED driver for Chrome OS.
- *
- *  Copyright (C) 2012 Google, Inc.
- *
- *  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.
- */
+// SPDX-License-Identifier: GPL-2.0+
+// Keyboard backlight LED driver for ChromeOS
+//
+// Copyright (C) 2012 Google, Inc.
 
 #include <linux/acpi.h>
 #include <linux/leds.h>
diff --git a/drivers/platform/chrome/wilco_ec/Kconfig b/drivers/platform/chrome/wilco_ec/Kconfig
new file mode 100644 (file)
index 0000000..e09e4ce
--- /dev/null
@@ -0,0 +1,20 @@
+config WILCO_EC
+       tristate "ChromeOS Wilco Embedded Controller"
+       depends on ACPI && X86 && CROS_EC_LPC && CROS_EC_LPC_MEC
+       help
+         If you say Y here, you get support for talking to the ChromeOS
+         Wilco EC over an eSPI bus. This uses a simple byte-level protocol
+         with a checksum.
+
+         To compile this driver as a module, choose M here: the
+         module will be called wilco_ec.
+
+config WILCO_EC_DEBUGFS
+       tristate "Enable raw access to EC via debugfs"
+       depends on WILCO_EC
+       help
+         If you say Y here, you get support for sending raw commands to
+         the Wilco EC via debugfs.  These commands do not do any byte
+         manipulation and allow for testing arbitrary commands.  This
+         interface is intended for debug only and will not be present
+         on production devices.
diff --git a/drivers/platform/chrome/wilco_ec/Makefile b/drivers/platform/chrome/wilco_ec/Makefile
new file mode 100644 (file)
index 0000000..063e7fb
--- /dev/null
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0
+
+wilco_ec-objs                          := core.o mailbox.o
+obj-$(CONFIG_WILCO_EC)                 += wilco_ec.o
+wilco_ec_debugfs-objs                  := debugfs.o
+obj-$(CONFIG_WILCO_EC_DEBUGFS)         += wilco_ec_debugfs.o
diff --git a/drivers/platform/chrome/wilco_ec/core.c b/drivers/platform/chrome/wilco_ec/core.c
new file mode 100644 (file)
index 0000000..05e1e2b
--- /dev/null
@@ -0,0 +1,136 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Core driver for Wilco Embedded Controller
+ *
+ * Copyright 2018 Google LLC
+ *
+ * This is the entry point for the drivers that control the Wilco EC.
+ * This driver is responsible for several tasks:
+ * - Initialize the register interface that is used by wilco_ec_mailbox()
+ * - Create a platform device which is picked up by the debugfs driver
+ * - Create a platform device which is picked up by the RTC driver
+ */
+
+#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/platform_data/wilco-ec.h>
+#include <linux/platform_device.h>
+
+#include "../cros_ec_lpc_mec.h"
+
+#define DRV_NAME "wilco-ec"
+
+static struct resource *wilco_get_resource(struct platform_device *pdev,
+                                          int index)
+{
+       struct device *dev = &pdev->dev;
+       struct resource *res;
+
+       res = platform_get_resource(pdev, IORESOURCE_IO, index);
+       if (!res) {
+               dev_dbg(dev, "Couldn't find IO resource %d\n", index);
+               return res;
+       }
+
+       return devm_request_region(dev, res->start, resource_size(res),
+                                  dev_name(dev));
+}
+
+static int wilco_ec_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct wilco_ec_device *ec;
+       int ret;
+
+       ec = devm_kzalloc(dev, sizeof(*ec), GFP_KERNEL);
+       if (!ec)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, ec);
+       ec->dev = dev;
+       mutex_init(&ec->mailbox_lock);
+
+       /* Largest data buffer size requirement is extended data response */
+       ec->data_size = sizeof(struct wilco_ec_response) +
+               EC_MAILBOX_DATA_SIZE_EXTENDED;
+       ec->data_buffer = devm_kzalloc(dev, ec->data_size, GFP_KERNEL);
+       if (!ec->data_buffer)
+               return -ENOMEM;
+
+       /* Prepare access to IO regions provided by ACPI */
+       ec->io_data = wilco_get_resource(pdev, 0);      /* Host Data */
+       ec->io_command = wilco_get_resource(pdev, 1);   /* Host Command */
+       ec->io_packet = wilco_get_resource(pdev, 2);    /* MEC EMI */
+       if (!ec->io_data || !ec->io_command || !ec->io_packet)
+               return -ENODEV;
+
+       /* Initialize cros_ec register interface for communication */
+       cros_ec_lpc_mec_init(ec->io_packet->start,
+                            ec->io_packet->start + EC_MAILBOX_DATA_SIZE);
+
+       /*
+        * Register a child device that will be found by the debugfs driver.
+        * Ignore failure.
+        */
+       ec->debugfs_pdev = platform_device_register_data(dev,
+                                                        "wilco-ec-debugfs",
+                                                        PLATFORM_DEVID_AUTO,
+                                                        NULL, 0);
+
+       /* Register a child device that will be found by the RTC driver. */
+       ec->rtc_pdev = platform_device_register_data(dev, "rtc-wilco-ec",
+                                                    PLATFORM_DEVID_AUTO,
+                                                    NULL, 0);
+       if (IS_ERR(ec->rtc_pdev)) {
+               dev_err(dev, "Failed to create RTC platform device\n");
+               ret = PTR_ERR(ec->rtc_pdev);
+               goto unregister_debugfs;
+       }
+
+       return 0;
+
+unregister_debugfs:
+       if (ec->debugfs_pdev)
+               platform_device_unregister(ec->debugfs_pdev);
+       cros_ec_lpc_mec_destroy();
+       return ret;
+}
+
+static int wilco_ec_remove(struct platform_device *pdev)
+{
+       struct wilco_ec_device *ec = platform_get_drvdata(pdev);
+
+       platform_device_unregister(ec->rtc_pdev);
+       if (ec->debugfs_pdev)
+               platform_device_unregister(ec->debugfs_pdev);
+
+       /* Teardown cros_ec interface */
+       cros_ec_lpc_mec_destroy();
+
+       return 0;
+}
+
+static const struct acpi_device_id wilco_ec_acpi_device_ids[] = {
+       { "GOOG000C", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(acpi, wilco_ec_acpi_device_ids);
+
+static struct platform_driver wilco_ec_driver = {
+       .driver = {
+               .name = DRV_NAME,
+               .acpi_match_table = wilco_ec_acpi_device_ids,
+       },
+       .probe = wilco_ec_probe,
+       .remove = wilco_ec_remove,
+};
+
+module_platform_driver(wilco_ec_driver);
+
+MODULE_AUTHOR("Nick Crews <ncrews@chromium.org>");
+MODULE_AUTHOR("Duncan Laurie <dlaurie@chromium.org>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("ChromeOS Wilco Embedded Controller driver");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/platform/chrome/wilco_ec/debugfs.c b/drivers/platform/chrome/wilco_ec/debugfs.c
new file mode 100644 (file)
index 0000000..c090db2
--- /dev/null
@@ -0,0 +1,238 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * debugfs attributes for Wilco EC
+ *
+ * Copyright 2019 Google LLC
+ *
+ * There is only one attribute used for debugging, called raw.
+ * You can write a hexadecimal sentence to raw, and that series of bytes
+ * will be sent to the EC. Then, you can read the bytes of response
+ * by reading from raw.
+ *
+ * For writing:
+ * Bytes 0-1 indicate the message type:
+ *         00 F0 = Execute Legacy Command
+ *         00 F2 = Read/Write NVRAM Property
+ * Byte 2 provides the command code
+ * Bytes 3+ consist of the data passed in the request
+ *
+ * When referencing the EC interface spec, byte 2 corresponds to MBOX[0],
+ * byte 3 corresponds to MBOX[1], etc.
+ *
+ * At least three bytes are required, for the msg type and command,
+ * with additional bytes optional for additional data.
+ *
+ * Example:
+ * // Request EC info type 3 (EC firmware build date)
+ * $ echo 00 f0 38 00 03 00 > raw
+ * // View the result. The decoded ASCII result "12/21/18" is
+ * // included after the raw hex.
+ * $ cat raw
+ * 00 31 32 2f 32 31 2f 31 38 00 38 00 01 00 2f 00  .12/21/18.8...
+ */
+
+#include <linux/ctype.h>
+#include <linux/debugfs.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/platform_data/wilco-ec.h>
+#include <linux/platform_device.h>
+
+#define DRV_NAME "wilco-ec-debugfs"
+
+/* The 256 raw bytes will take up more space when represented as a hex string */
+#define FORMATTED_BUFFER_SIZE (EC_MAILBOX_DATA_SIZE_EXTENDED * 4)
+
+struct wilco_ec_debugfs {
+       struct wilco_ec_device *ec;
+       struct dentry *dir;
+       size_t response_size;
+       u8 raw_data[EC_MAILBOX_DATA_SIZE_EXTENDED];
+       u8 formatted_data[FORMATTED_BUFFER_SIZE];
+};
+static struct wilco_ec_debugfs *debug_info;
+
+/**
+ * parse_hex_sentence() - Convert a ascii hex representation into byte array.
+ * @in: Input buffer of ascii.
+ * @isize: Length of input buffer.
+ * @out: Output buffer.
+ * @osize: Length of output buffer, e.g. max number of bytes to parse.
+ *
+ * An valid input is a series of ascii hexadecimal numbers, separated by spaces.
+ * An example valid input is
+ * "   00 f2 0    000076 6 0  ff"
+ *
+ * If an individual "word" within the hex sentence is longer than MAX_WORD_SIZE,
+ * then the sentence is illegal, and parsing will fail.
+ *
+ * Return: Number of bytes parsed, or negative error code on failure.
+ */
+static int parse_hex_sentence(const char *in, int isize, u8 *out, int osize)
+{
+       int n_parsed = 0;
+       int word_start = 0;
+       int word_end;
+       int word_len;
+       /* Temp buffer for holding a "word" of chars that represents one byte */
+       #define MAX_WORD_SIZE 16
+       char tmp[MAX_WORD_SIZE + 1];
+       u8 byte;
+
+       while (word_start < isize && n_parsed < osize) {
+               /* Find the start of the next word */
+               while (word_start < isize && isspace(in[word_start]))
+                       word_start++;
+                /* reached the end of the input before next word? */
+               if (word_start >= isize)
+                       break;
+
+               /* Find the end of this word */
+               word_end = word_start;
+               while (word_end < isize && !isspace(in[word_end]))
+                       word_end++;
+
+               /* Copy to a tmp NULL terminated string */
+               word_len = word_end - word_start;
+               if (word_len > MAX_WORD_SIZE)
+                       return -EINVAL;
+               memcpy(tmp, in + word_start, word_len);
+               tmp[word_len] = '\0';
+
+               /*
+                * Convert from hex string, place in output. If fails to parse,
+                * just return -EINVAL because specific error code is only
+                * relevant for this one word, returning it would be confusing.
+                */
+               if (kstrtou8(tmp, 16, &byte))
+                       return -EINVAL;
+               out[n_parsed++] = byte;
+
+               word_start = word_end;
+       }
+       return n_parsed;
+}
+
+/* The message type takes up two bytes*/
+#define TYPE_AND_DATA_SIZE ((EC_MAILBOX_DATA_SIZE) + 2)
+
+static ssize_t raw_write(struct file *file, const char __user *user_buf,
+                        size_t count, loff_t *ppos)
+{
+       char *buf = debug_info->formatted_data;
+       struct wilco_ec_message msg;
+       u8 request_data[TYPE_AND_DATA_SIZE];
+       ssize_t kcount;
+       int ret;
+
+       if (count > FORMATTED_BUFFER_SIZE)
+               return -EINVAL;
+
+       kcount = simple_write_to_buffer(buf, FORMATTED_BUFFER_SIZE, ppos,
+                                       user_buf, count);
+       if (kcount < 0)
+               return kcount;
+
+       ret = parse_hex_sentence(buf, kcount, request_data, TYPE_AND_DATA_SIZE);
+       if (ret < 0)
+               return ret;
+       /* Need at least two bytes for message type and one for command */
+       if (ret < 3)
+               return -EINVAL;
+
+       /* Clear response data buffer */
+       memset(debug_info->raw_data, '\0', EC_MAILBOX_DATA_SIZE_EXTENDED);
+
+       msg.type = request_data[0] << 8 | request_data[1];
+       msg.flags = WILCO_EC_FLAG_RAW;
+       msg.command = request_data[2];
+       msg.request_data = ret > 3 ? request_data + 3 : 0;
+       msg.request_size = ret - 3;
+       msg.response_data = debug_info->raw_data;
+       msg.response_size = EC_MAILBOX_DATA_SIZE;
+
+       /* Telemetry commands use extended response data */
+       if (msg.type == WILCO_EC_MSG_TELEMETRY_LONG) {
+               msg.flags |= WILCO_EC_FLAG_EXTENDED_DATA;
+               msg.response_size = EC_MAILBOX_DATA_SIZE_EXTENDED;
+       }
+
+       ret = wilco_ec_mailbox(debug_info->ec, &msg);
+       if (ret < 0)
+               return ret;
+       debug_info->response_size = ret;
+
+       return count;
+}
+
+static ssize_t raw_read(struct file *file, char __user *user_buf, size_t count,
+                       loff_t *ppos)
+{
+       int fmt_len = 0;
+
+       if (debug_info->response_size) {
+               fmt_len = hex_dump_to_buffer(debug_info->raw_data,
+                                            debug_info->response_size,
+                                            16, 1, debug_info->formatted_data,
+                                            FORMATTED_BUFFER_SIZE, true);
+               /* Only return response the first time it is read */
+               debug_info->response_size = 0;
+       }
+
+       return simple_read_from_buffer(user_buf, count, ppos,
+                                      debug_info->formatted_data, fmt_len);
+}
+
+static const struct file_operations fops_raw = {
+       .owner = THIS_MODULE,
+       .read = raw_read,
+       .write = raw_write,
+       .llseek = no_llseek,
+};
+
+/**
+ * wilco_ec_debugfs_probe() - Create the debugfs node
+ * @pdev: The platform device, probably created in core.c
+ *
+ * Try to create a debugfs node. If it fails, then we don't want to change
+ * behavior at all, this is for debugging after all. Just fail silently.
+ *
+ * Return: 0 always.
+ */
+static int wilco_ec_debugfs_probe(struct platform_device *pdev)
+{
+       struct wilco_ec_device *ec = dev_get_drvdata(pdev->dev.parent);
+
+       debug_info = devm_kzalloc(&pdev->dev, sizeof(*debug_info), GFP_KERNEL);
+       if (!debug_info)
+               return 0;
+       debug_info->ec = ec;
+       debug_info->dir = debugfs_create_dir("wilco_ec", NULL);
+       if (!debug_info->dir)
+               return 0;
+       debugfs_create_file("raw", 0644, debug_info->dir, NULL, &fops_raw);
+
+       return 0;
+}
+
+static int wilco_ec_debugfs_remove(struct platform_device *pdev)
+{
+       debugfs_remove_recursive(debug_info->dir);
+
+       return 0;
+}
+
+static struct platform_driver wilco_ec_debugfs_driver = {
+       .driver = {
+               .name = DRV_NAME,
+       },
+       .probe = wilco_ec_debugfs_probe,
+       .remove = wilco_ec_debugfs_remove,
+};
+
+module_platform_driver(wilco_ec_debugfs_driver);
+
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_AUTHOR("Nick Crews <ncrews@chromium.org>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Wilco EC debugfs driver");
diff --git a/drivers/platform/chrome/wilco_ec/mailbox.c b/drivers/platform/chrome/wilco_ec/mailbox.c
new file mode 100644 (file)
index 0000000..f6ff29a
--- /dev/null
@@ -0,0 +1,237 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Mailbox interface for Wilco Embedded Controller
+ *
+ * Copyright 2018 Google LLC
+ *
+ * The Wilco EC is similar to a typical ChromeOS embedded controller.
+ * It uses the same MEC based low-level communication and a similar
+ * protocol, but with some important differences.  The EC firmware does
+ * not support the same mailbox commands so it is not registered as a
+ * cros_ec device type.
+ *
+ * Most messages follow a standard format, but there are some exceptions
+ * and an interface is provided to do direct/raw transactions that do not
+ * make assumptions about byte placement.
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/platform_data/wilco-ec.h>
+#include <linux/platform_device.h>
+
+#include "../cros_ec_lpc_mec.h"
+
+/* Version of mailbox interface */
+#define EC_MAILBOX_VERSION             0
+
+/* Command to start mailbox transaction */
+#define EC_MAILBOX_START_COMMAND       0xda
+
+/* Version of EC protocol */
+#define EC_MAILBOX_PROTO_VERSION       3
+
+/* Number of header bytes to be counted as data bytes */
+#define EC_MAILBOX_DATA_EXTRA          2
+
+/* Maximum timeout */
+#define EC_MAILBOX_TIMEOUT             HZ
+
+/* EC response flags */
+#define EC_CMDR_DATA           BIT(0)  /* Data ready for host to read */
+#define EC_CMDR_PENDING                BIT(1)  /* Write pending to EC */
+#define EC_CMDR_BUSY           BIT(2)  /* EC is busy processing a command */
+#define EC_CMDR_CMD            BIT(3)  /* Last host write was a command */
+
+/**
+ * wilco_ec_response_timed_out() - Wait for EC response.
+ * @ec: EC device.
+ *
+ * Return: true if EC timed out, false if EC did not time out.
+ */
+static bool wilco_ec_response_timed_out(struct wilco_ec_device *ec)
+{
+       unsigned long timeout = jiffies + EC_MAILBOX_TIMEOUT;
+
+       do {
+               if (!(inb(ec->io_command->start) &
+                     (EC_CMDR_PENDING | EC_CMDR_BUSY)))
+                       return false;
+               usleep_range(100, 200);
+       } while (time_before(jiffies, timeout));
+
+       return true;
+}
+
+/**
+ * wilco_ec_checksum() - Compute 8-bit checksum over data range.
+ * @data: Data to checksum.
+ * @size: Number of bytes to checksum.
+ *
+ * Return: 8-bit checksum of provided data.
+ */
+static u8 wilco_ec_checksum(const void *data, size_t size)
+{
+       u8 *data_bytes = (u8 *)data;
+       u8 checksum = 0;
+       size_t i;
+
+       for (i = 0; i < size; i++)
+               checksum += data_bytes[i];
+
+       return checksum;
+}
+
+/**
+ * wilco_ec_prepare() - Prepare the request structure for the EC.
+ * @msg: EC message with request information.
+ * @rq: EC request structure to fill.
+ */
+static void wilco_ec_prepare(struct wilco_ec_message *msg,
+                            struct wilco_ec_request *rq)
+{
+       memset(rq, 0, sizeof(*rq));
+
+       /* Handle messages without trimming bytes from the request */
+       if (msg->request_size && msg->flags & WILCO_EC_FLAG_RAW_REQUEST) {
+               rq->reserved_raw = *(u8 *)msg->request_data;
+               msg->request_size--;
+               memmove(msg->request_data, msg->request_data + 1,
+                       msg->request_size);
+       }
+
+       /* Fill in request packet */
+       rq->struct_version = EC_MAILBOX_PROTO_VERSION;
+       rq->mailbox_id = msg->type;
+       rq->mailbox_version = EC_MAILBOX_VERSION;
+       rq->data_size = msg->request_size + EC_MAILBOX_DATA_EXTRA;
+       rq->command = msg->command;
+
+       /* Checksum header and data */
+       rq->checksum = wilco_ec_checksum(rq, sizeof(*rq));
+       rq->checksum += wilco_ec_checksum(msg->request_data, msg->request_size);
+       rq->checksum = -rq->checksum;
+}
+
+/**
+ * wilco_ec_transfer() - Perform actual data transfer.
+ * @ec: EC device.
+ * @msg: EC message data for request and response.
+ * @rq: Filled in request structure
+ *
+ * Context: ec->mailbox_lock should be held while using this function.
+ * Return: number of bytes received or negative error code on failure.
+ */
+static int wilco_ec_transfer(struct wilco_ec_device *ec,
+                            struct wilco_ec_message *msg,
+                            struct wilco_ec_request *rq)
+{
+       struct wilco_ec_response *rs;
+       u8 checksum;
+       u8 flag;
+       size_t size;
+
+       /* Write request header, then data */
+       cros_ec_lpc_io_bytes_mec(MEC_IO_WRITE, 0, sizeof(*rq), (u8 *)rq);
+       cros_ec_lpc_io_bytes_mec(MEC_IO_WRITE, sizeof(*rq), msg->request_size,
+                                msg->request_data);
+
+       /* Start the command */
+       outb(EC_MAILBOX_START_COMMAND, ec->io_command->start);
+
+       /* For some commands (eg shutdown) the EC will not respond, that's OK */
+       if (msg->flags & WILCO_EC_FLAG_NO_RESPONSE) {
+               dev_dbg(ec->dev, "EC does not respond to this command\n");
+               return 0;
+       }
+
+       /* Wait for it to complete */
+       if (wilco_ec_response_timed_out(ec)) {
+               dev_dbg(ec->dev, "response timed out\n");
+               return -ETIMEDOUT;
+       }
+
+       /* Check result */
+       flag = inb(ec->io_data->start);
+       if (flag) {
+               dev_dbg(ec->dev, "bad response: 0x%02x\n", flag);
+               return -EIO;
+       }
+
+       if (msg->flags & WILCO_EC_FLAG_EXTENDED_DATA)
+               size = EC_MAILBOX_DATA_SIZE_EXTENDED;
+       else
+               size = EC_MAILBOX_DATA_SIZE;
+
+       /* Read back response */
+       rs = ec->data_buffer;
+       checksum = cros_ec_lpc_io_bytes_mec(MEC_IO_READ, 0,
+                                           sizeof(*rs) + size, (u8 *)rs);
+       if (checksum) {
+               dev_dbg(ec->dev, "bad packet checksum 0x%02x\n", rs->checksum);
+               return -EBADMSG;
+       }
+
+       /* Check that the EC reported success */
+       msg->result = rs->result;
+       if (msg->result) {
+               dev_dbg(ec->dev, "bad response: 0x%02x\n", msg->result);
+               return -EBADMSG;
+       }
+
+       /* Check the returned data size, skipping the header */
+       if (rs->data_size != size) {
+               dev_dbg(ec->dev, "unexpected packet size (%u != %zu)",
+                       rs->data_size, size);
+               return -EMSGSIZE;
+       }
+
+       /* Skip 1 response data byte unless specified */
+       size = (msg->flags & WILCO_EC_FLAG_RAW_RESPONSE) ? 0 : 1;
+       if ((ssize_t) rs->data_size - size < msg->response_size) {
+               dev_dbg(ec->dev, "response data too short (%zd < %zu)",
+                       (ssize_t) rs->data_size - size, msg->response_size);
+               return -EMSGSIZE;
+       }
+
+       /* Ignore response data bytes as requested */
+       memcpy(msg->response_data, rs->data + size, msg->response_size);
+
+       /* Return actual amount of data received */
+       return msg->response_size;
+}
+
+/**
+ * wilco_ec_mailbox() - Send EC request and receive EC response.
+ * @ec: EC device.
+ * @msg: EC message data for request and response.
+ *
+ * On entry msg->type, msg->flags, msg->command, msg->request_size,
+ * msg->response_size, and msg->request_data should all be filled in.
+ *
+ * On exit msg->result and msg->response_data will be filled.
+ *
+ * Return: number of bytes received or negative error code on failure.
+ */
+int wilco_ec_mailbox(struct wilco_ec_device *ec, struct wilco_ec_message *msg)
+{
+       struct wilco_ec_request *rq;
+       int ret;
+
+       dev_dbg(ec->dev, "cmd=%02x type=%04x flags=%02x rslen=%zu rqlen=%zu\n",
+               msg->command, msg->type, msg->flags, msg->response_size,
+               msg->request_size);
+
+       /* Prepare request packet */
+       rq = ec->data_buffer;
+       wilco_ec_prepare(msg, rq);
+
+       mutex_lock(&ec->mailbox_lock);
+       ret = wilco_ec_transfer(ec, msg, rq);
+       mutex_unlock(&ec->mailbox_lock);
+
+       return ret;
+
+}
+EXPORT_SYMBOL_GPL(wilco_ec_mailbox);
index e1a1f2b1cbbab6a8015d3261cee88db6f252af82..a71734c416939354129253af00090975ff0f1b5e 100644 (file)
@@ -1864,4 +1864,15 @@ config RTC_DRV_GOLDFISH
          Goldfish is a code name for the virtual platform developed by Google
          for Android emulation.
 
+config RTC_DRV_WILCO_EC
+       tristate "Wilco EC RTC"
+       depends on WILCO_EC
+       default m
+       help
+         If you say yes here, you get read/write support for the Real Time
+         Clock on the Wilco Embedded Controller (Wilco is a kind of Chromebook)
+
+         This can also be built as a module. If so, the module will
+         be named "rtc_wilco_ec".
+
 endif # RTC_CLASS
index 1bf9f75a7865431295db1e8ae7ac09ba3d69195b..fe3962496685a68a5cbe130e419c6021f052be27 100644 (file)
@@ -177,6 +177,7 @@ obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o
 obj-$(CONFIG_RTC_DRV_VR41XX)   += rtc-vr41xx.o
 obj-$(CONFIG_RTC_DRV_VRTC)     += rtc-mrst.o
 obj-$(CONFIG_RTC_DRV_VT8500)   += rtc-vt8500.o
+obj-$(CONFIG_RTC_DRV_WILCO_EC) += rtc-wilco-ec.o
 obj-$(CONFIG_RTC_DRV_WM831X)   += rtc-wm831x.o
 obj-$(CONFIG_RTC_DRV_WM8350)   += rtc-wm8350.o
 obj-$(CONFIG_RTC_DRV_X1205)    += rtc-x1205.o
diff --git a/drivers/rtc/rtc-wilco-ec.c b/drivers/rtc/rtc-wilco-ec.c
new file mode 100644 (file)
index 0000000..e62bda0
--- /dev/null
@@ -0,0 +1,177 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * RTC interface for Wilco Embedded Controller with R/W abilities
+ *
+ * Copyright 2018 Google LLC
+ *
+ * The corresponding platform device is typically registered in
+ * drivers/platform/chrome/wilco_ec/core.c
+ */
+
+#include <linux/bcd.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/wilco-ec.h>
+#include <linux/rtc.h>
+#include <linux/timekeeping.h>
+
+#define EC_COMMAND_CMOS                        0x7c
+#define EC_CMOS_TOD_WRITE              0x02
+#define EC_CMOS_TOD_READ               0x08
+
+/**
+ * struct ec_rtc_read - Format of RTC returned by EC.
+ * @second: Second value (0..59)
+ * @minute: Minute value (0..59)
+ * @hour: Hour value (0..23)
+ * @day: Day value (1..31)
+ * @month: Month value (1..12)
+ * @year: Year value (full year % 100)
+ * @century: Century value (full year / 100)
+ *
+ * All values are presented in binary (not BCD).
+ */
+struct ec_rtc_read {
+       u8 second;
+       u8 minute;
+       u8 hour;
+       u8 day;
+       u8 month;
+       u8 year;
+       u8 century;
+} __packed;
+
+/**
+ * struct ec_rtc_write - Format of RTC sent to the EC.
+ * @param: EC_CMOS_TOD_WRITE
+ * @century: Century value (full year / 100)
+ * @year: Year value (full year % 100)
+ * @month: Month value (1..12)
+ * @day: Day value (1..31)
+ * @hour: Hour value (0..23)
+ * @minute: Minute value (0..59)
+ * @second: Second value (0..59)
+ * @weekday: Day of the week (0=Saturday)
+ *
+ * All values are presented in BCD.
+ */
+struct ec_rtc_write {
+       u8 param;
+       u8 century;
+       u8 year;
+       u8 month;
+       u8 day;
+       u8 hour;
+       u8 minute;
+       u8 second;
+       u8 weekday;
+} __packed;
+
+static int wilco_ec_rtc_read(struct device *dev, struct rtc_time *tm)
+{
+       struct wilco_ec_device *ec = dev_get_drvdata(dev->parent);
+       u8 param = EC_CMOS_TOD_READ;
+       struct ec_rtc_read rtc;
+       struct wilco_ec_message msg = {
+               .type = WILCO_EC_MSG_LEGACY,
+               .flags = WILCO_EC_FLAG_RAW_RESPONSE,
+               .command = EC_COMMAND_CMOS,
+               .request_data = &param,
+               .request_size = sizeof(param),
+               .response_data = &rtc,
+               .response_size = sizeof(rtc),
+       };
+       int ret;
+
+       ret = wilco_ec_mailbox(ec, &msg);
+       if (ret < 0)
+               return ret;
+
+       tm->tm_sec      = rtc.second;
+       tm->tm_min      = rtc.minute;
+       tm->tm_hour     = rtc.hour;
+       tm->tm_mday     = rtc.day;
+       tm->tm_mon      = rtc.month - 1;
+       tm->tm_year     = rtc.year + (rtc.century * 100) - 1900;
+       tm->tm_yday     = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year);
+
+       /* Don't compute day of week, we don't need it. */
+       tm->tm_wday = -1;
+
+       return 0;
+}
+
+static int wilco_ec_rtc_write(struct device *dev, struct rtc_time *tm)
+{
+       struct wilco_ec_device *ec = dev_get_drvdata(dev->parent);
+       struct ec_rtc_write rtc;
+       struct wilco_ec_message msg = {
+               .type = WILCO_EC_MSG_LEGACY,
+               .flags = WILCO_EC_FLAG_RAW_RESPONSE,
+               .command = EC_COMMAND_CMOS,
+               .request_data = &rtc,
+               .request_size = sizeof(rtc),
+       };
+       int year = tm->tm_year + 1900;
+       /*
+        * Convert from 0=Sunday to 0=Saturday for the EC
+        * We DO need to set weekday because the EC controls battery charging
+        * schedules that depend on the day of the week.
+        */
+       int wday = tm->tm_wday == 6 ? 0 : tm->tm_wday + 1;
+       int ret;
+
+       rtc.param       = EC_CMOS_TOD_WRITE;
+       rtc.century     = bin2bcd(year / 100);
+       rtc.year        = bin2bcd(year % 100);
+       rtc.month       = bin2bcd(tm->tm_mon + 1);
+       rtc.day         = bin2bcd(tm->tm_mday);
+       rtc.hour        = bin2bcd(tm->tm_hour);
+       rtc.minute      = bin2bcd(tm->tm_min);
+       rtc.second      = bin2bcd(tm->tm_sec);
+       rtc.weekday     = bin2bcd(wday);
+
+       ret = wilco_ec_mailbox(ec, &msg);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static const struct rtc_class_ops wilco_ec_rtc_ops = {
+       .read_time = wilco_ec_rtc_read,
+       .set_time = wilco_ec_rtc_write,
+};
+
+static int wilco_ec_rtc_probe(struct platform_device *pdev)
+{
+       struct rtc_device *rtc;
+
+       rtc = devm_rtc_allocate_device(&pdev->dev);
+       if (IS_ERR(rtc))
+               return PTR_ERR(rtc);
+
+       rtc->ops = &wilco_ec_rtc_ops;
+       /* EC only supports this century */
+       rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
+       rtc->range_max = RTC_TIMESTAMP_END_2099;
+       rtc->owner = THIS_MODULE;
+
+       return rtc_register_device(rtc);
+}
+
+static struct platform_driver wilco_ec_rtc_driver = {
+       .driver = {
+               .name = "rtc-wilco-ec",
+       },
+       .probe = wilco_ec_rtc_probe,
+};
+
+module_platform_driver(wilco_ec_rtc_driver);
+
+MODULE_ALIAS("platform:rtc-wilco-ec");
+MODULE_AUTHOR("Nick Crews <ncrews@chromium.org>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Wilco EC RTC driver");
diff --git a/include/linux/platform_data/wilco-ec.h b/include/linux/platform_data/wilco-ec.h
new file mode 100644 (file)
index 0000000..446473a
--- /dev/null
@@ -0,0 +1,144 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * ChromeOS Wilco Embedded Controller
+ *
+ * Copyright 2018 Google LLC
+ */
+
+#ifndef WILCO_EC_H
+#define WILCO_EC_H
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+
+/* Message flags for using the mailbox() interface */
+#define WILCO_EC_FLAG_NO_RESPONSE      BIT(0) /* EC does not respond */
+#define WILCO_EC_FLAG_EXTENDED_DATA    BIT(1) /* EC returns 256 data bytes */
+#define WILCO_EC_FLAG_RAW_REQUEST      BIT(2) /* Do not trim request data */
+#define WILCO_EC_FLAG_RAW_RESPONSE     BIT(3) /* Do not trim response data */
+#define WILCO_EC_FLAG_RAW              (WILCO_EC_FLAG_RAW_REQUEST | \
+                                        WILCO_EC_FLAG_RAW_RESPONSE)
+
+/* Normal commands have a maximum 32 bytes of data */
+#define EC_MAILBOX_DATA_SIZE           32
+/* Extended commands have 256 bytes of response data */
+#define EC_MAILBOX_DATA_SIZE_EXTENDED  256
+
+/**
+ * struct wilco_ec_device - Wilco Embedded Controller handle.
+ * @dev: Device handle.
+ * @mailbox_lock: Mutex to ensure one mailbox command at a time.
+ * @io_command: I/O port for mailbox command.  Provided by ACPI.
+ * @io_data: I/O port for mailbox data.  Provided by ACPI.
+ * @io_packet: I/O port for mailbox packet data.  Provided by ACPI.
+ * @data_buffer: Buffer used for EC communication.  The same buffer
+ *               is used to hold the request and the response.
+ * @data_size: Size of the data buffer used for EC communication.
+ * @debugfs_pdev: The child platform_device used by the debugfs sub-driver.
+ * @rtc_pdev: The child platform_device used by the RTC sub-driver.
+ */
+struct wilco_ec_device {
+       struct device *dev;
+       struct mutex mailbox_lock;
+       struct resource *io_command;
+       struct resource *io_data;
+       struct resource *io_packet;
+       void *data_buffer;
+       size_t data_size;
+       struct platform_device *debugfs_pdev;
+       struct platform_device *rtc_pdev;
+};
+
+/**
+ * struct wilco_ec_request - Mailbox request message format.
+ * @struct_version: Should be %EC_MAILBOX_PROTO_VERSION
+ * @checksum: Sum of all bytes must be 0.
+ * @mailbox_id: Mailbox identifier, specifies the command set.
+ * @mailbox_version: Mailbox interface version %EC_MAILBOX_VERSION
+ * @reserved: Set to zero.
+ * @data_size: Length of request, data + last 2 bytes of the header.
+ * @command: Mailbox command code, unique for each mailbox_id set.
+ * @reserved_raw: Set to zero for most commands, but is used by
+ *                some command types and for raw commands.
+ */
+struct wilco_ec_request {
+       u8 struct_version;
+       u8 checksum;
+       u16 mailbox_id;
+       u8 mailbox_version;
+       u8 reserved;
+       u16 data_size;
+       u8 command;
+       u8 reserved_raw;
+} __packed;
+
+/**
+ * struct wilco_ec_response - Mailbox response message format.
+ * @struct_version: Should be %EC_MAILBOX_PROTO_VERSION
+ * @checksum: Sum of all bytes must be 0.
+ * @result: Result code from the EC.  Non-zero indicates an error.
+ * @data_size: Length of the response data buffer.
+ * @reserved: Set to zero.
+ * @mbox0: EC returned data at offset 0 is unused (always 0) so this byte
+ *         is treated as part of the header instead of the data.
+ * @data: Response data buffer.  Max size is %EC_MAILBOX_DATA_SIZE_EXTENDED.
+ */
+struct wilco_ec_response {
+       u8 struct_version;
+       u8 checksum;
+       u16 result;
+       u16 data_size;
+       u8 reserved[2];
+       u8 mbox0;
+       u8 data[0];
+} __packed;
+
+/**
+ * enum wilco_ec_msg_type - Message type to select a set of command codes.
+ * @WILCO_EC_MSG_LEGACY: Legacy EC messages for standard EC behavior.
+ * @WILCO_EC_MSG_PROPERTY: Get/Set/Sync EC controlled NVRAM property.
+ * @WILCO_EC_MSG_TELEMETRY_SHORT: 32 bytes of telemetry data provided by the EC.
+ * @WILCO_EC_MSG_TELEMETRY_LONG: 256 bytes of telemetry data provided by the EC.
+ */
+enum wilco_ec_msg_type {
+       WILCO_EC_MSG_LEGACY = 0x00f0,
+       WILCO_EC_MSG_PROPERTY = 0x00f2,
+       WILCO_EC_MSG_TELEMETRY_SHORT = 0x00f5,
+       WILCO_EC_MSG_TELEMETRY_LONG = 0x00f6,
+};
+
+/**
+ * struct wilco_ec_message - Request and response message.
+ * @type: Mailbox message type.
+ * @flags: Message flags, e.g. %WILCO_EC_FLAG_NO_RESPONSE.
+ * @command: Mailbox command code.
+ * @result: Result code from the EC.  Non-zero indicates an error.
+ * @request_size: Number of bytes to send to the EC.
+ * @request_data: Buffer containing the request data.
+ * @response_size: Number of bytes expected from the EC.
+ *                 This is 32 by default and 256 if the flag
+ *                 is set for %WILCO_EC_FLAG_EXTENDED_DATA
+ * @response_data: Buffer containing the response data, should be
+ *                 response_size bytes and allocated by caller.
+ */
+struct wilco_ec_message {
+       enum wilco_ec_msg_type type;
+       u8 flags;
+       u8 command;
+       u8 result;
+       size_t request_size;
+       void *request_data;
+       size_t response_size;
+       void *response_data;
+};
+
+/**
+ * wilco_ec_mailbox() - Send request to the EC and receive the response.
+ * @ec: Wilco EC device.
+ * @msg: Wilco EC message.
+ *
+ * Return: Number of bytes received or negative error code on failure.
+ */
+int wilco_ec_mailbox(struct wilco_ec_device *ec, struct wilco_ec_message *msg);
+
+#endif /* WILCO_EC_H */