chrome platform changes for v5.1
1. SPDX identifier cleanup for platform/chrome 2. Cleanup series between mfd and chrome/platform, moving cros-ec attributes from mfd/cros_ec_dev to sub-drivers in platform/chrome. 3. Wilco EC driver 4. Maintainership change to new group repository. -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEE6gYDF28Li+nEiKLaHwn1ewov5lgFAlyG4dIACgkQHwn1ewov 5lhoqA//SXO5HU1qkhfvwUKyNsYxtIj4wDQF+j9tAPbVaOOaztq0b5D1PQgDGcEL SDl9FAXZtwhmPr5xiGPrPUxwn4JG+tUcgSSgIOCtClpA/SZUPt2wekAB64hLt1ui nkBRSgeRnXeeRE0nDh7EUrwAeaYj6yCg4AS8FMHmjWTG0tI6iivhuc39v/zDV8Br f4chOu/KEWS/EhItVlDBHE0mYDW2JGLSD3nqJR9MdujvYzbkN5WusJIXBDK6MOUl z1gqptVYyq/FQOQOCZ+vHjTNVYQ3N3NbPOnnQn4xAyYiqTQJVJv+x6dd7htncjVO 567PFbbqbKzqrGWZOrdksxVa4JkIGfcgNG2mskRYKpEtHVOpMlHxwHqKv/93TQvw F0z4+43ZeAo0Fx2k+oOiDylpClDvUVOeH0z5suqIK15MZbpfWZF6d38Pz1Zwd8hY 0TEldpyH83HiXylEuYabBwq3ABfj4VncYcMWfaW517LUrnH9nkJDNOlXQFreGTPt uHQPz+Xzfirk9wNwlEtfhqh3fjRWIfmiHc8bLmCB2XuJqavF0pozoQnJprw+72LR h4ALkUBr8laVfXYgG8SzNm/K4DlMjKqvJRY6m2b7AY8CTVgMur7ct0WJsvmECF+4 2XDDvHwkQJt3XifVLpLgFRfR5YRlFxjwMNS8Zq0Bb/gjRqSSCo4= =2nC0 -----END PGP SIGNATURE----- Merge tag 'tag-chrome-platform-for-v5.1' of git://git.kernel.org/pub/scm/linux/kernel/git/chrome-platform/linux 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
This commit is contained in:
commit
f47d633134
23
Documentation/ABI/testing/debugfs-wilco-ec
Normal file
23
Documentation/ABI/testing/debugfs-wilco-ec
Normal file
@ -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...
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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/
|
||||
|
@ -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");
|
||||
|
@ -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>
|
||||
|
@ -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");
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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)
|
||||
int in_range = cros_ec_lpc_mec_in_range(offset, length);
|
||||
|
||||
if (in_range < 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;
|
||||
|
||||
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))
|
||||
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)
|
||||
int in_range = cros_ec_lpc_mec_in_range(offset, length);
|
||||
|
||||
if (in_range < 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;
|
||||
|
||||
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))
|
||||
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)
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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");
|
||||
|
@ -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);
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
20
drivers/platform/chrome/wilco_ec/Kconfig
Normal file
20
drivers/platform/chrome/wilco_ec/Kconfig
Normal file
@ -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.
|
6
drivers/platform/chrome/wilco_ec/Makefile
Normal file
6
drivers/platform/chrome/wilco_ec/Makefile
Normal file
@ -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
|
136
drivers/platform/chrome/wilco_ec/core.c
Normal file
136
drivers/platform/chrome/wilco_ec/core.c
Normal file
@ -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);
|
238
drivers/platform/chrome/wilco_ec/debugfs.c
Normal file
238
drivers/platform/chrome/wilco_ec/debugfs.c
Normal file
@ -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");
|
237
drivers/platform/chrome/wilco_ec/mailbox.c
Normal file
237
drivers/platform/chrome/wilco_ec/mailbox.c
Normal file
@ -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);
|
@ -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
|
||||
|
@ -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
|
||||
|
177
drivers/rtc/rtc-wilco-ec.c
Normal file
177
drivers/rtc/rtc-wilco-ec.c
Normal file
@ -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 = ¶m,
|
||||
.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");
|
144
include/linux/platform_data/wilco-ec.h
Normal file
144
include/linux/platform_data/wilco-ec.h
Normal file
@ -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 */
|
Loading…
x
Reference in New Issue
Block a user