diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-03-12 12:46:32 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-03-12 12:46:32 -0400 |
| commit | f47d633134f7033e3d0c667419d9f8afd69e308d (patch) | |
| tree | a5242d86288599fda63ed79b2d131f5a298bb66f /drivers | |
| parent | 004cc08675b761fd82288bab1b5ba5e1ca746eca (diff) | |
| parent | 2794449576a6024e203eca5cc2c1a3ae33102b8e (diff) | |
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
Diffstat (limited to 'drivers')
24 files changed, 980 insertions, 311 deletions
diff --git a/drivers/platform/chrome/Kconfig b/drivers/platform/chrome/Kconfig index 5e2fde5ff63d..9186d81a51cc 100644 --- a/drivers/platform/chrome/Kconfig +++ b/drivers/platform/chrome/Kconfig | |||
| @@ -152,4 +152,6 @@ config CROS_EC_SYSFS | |||
| 152 | To compile this driver as a module, choose M here: the | 152 | To compile this driver as a module, choose M here: the |
| 153 | module will be called cros_ec_sysfs. | 153 | module will be called cros_ec_sysfs. |
| 154 | 154 | ||
| 155 | source "drivers/platform/chrome/wilco_ec/Kconfig" | ||
| 156 | |||
| 155 | endif # CHROMEOS_PLATFORMS | 157 | endif # CHROMEOS_PLATFORMS |
diff --git a/drivers/platform/chrome/Makefile b/drivers/platform/chrome/Makefile index fdbee501931b..1e2f0029b597 100644 --- a/drivers/platform/chrome/Makefile +++ b/drivers/platform/chrome/Makefile | |||
| @@ -14,3 +14,5 @@ obj-$(CONFIG_CROS_EC_LIGHTBAR) += cros_ec_lightbar.o | |||
| 14 | obj-$(CONFIG_CROS_EC_VBC) += cros_ec_vbc.o | 14 | obj-$(CONFIG_CROS_EC_VBC) += cros_ec_vbc.o |
| 15 | obj-$(CONFIG_CROS_EC_DEBUGFS) += cros_ec_debugfs.o | 15 | obj-$(CONFIG_CROS_EC_DEBUGFS) += cros_ec_debugfs.o |
| 16 | obj-$(CONFIG_CROS_EC_SYSFS) += cros_ec_sysfs.o | 16 | obj-$(CONFIG_CROS_EC_SYSFS) += cros_ec_sysfs.o |
| 17 | |||
| 18 | obj-$(CONFIG_WILCO_EC) += wilco_ec/ | ||
diff --git a/drivers/platform/chrome/chromeos_pstore.c b/drivers/platform/chrome/chromeos_pstore.c index b0693fdec8c6..d13770785fb5 100644 --- a/drivers/platform/chrome/chromeos_pstore.c +++ b/drivers/platform/chrome/chromeos_pstore.c | |||
| @@ -1,12 +1,7 @@ | |||
| 1 | /* | 1 | // SPDX-License-Identifier: GPL-2.0 |
| 2 | * chromeos_pstore.c - Driver to instantiate Chromebook ramoops device | 2 | // Driver to instantiate Chromebook ramoops device. |
| 3 | * | 3 | // |
| 4 | * Copyright (C) 2013 Google, Inc. | 4 | // Copyright (C) 2013 Google, Inc. |
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation, version 2 of the License. | ||
| 9 | */ | ||
| 10 | 5 | ||
| 11 | #include <linux/acpi.h> | 6 | #include <linux/acpi.h> |
| 12 | #include <linux/dmi.h> | 7 | #include <linux/dmi.h> |
| @@ -138,5 +133,5 @@ static void __exit chromeos_pstore_exit(void) | |||
| 138 | module_init(chromeos_pstore_init); | 133 | module_init(chromeos_pstore_init); |
| 139 | module_exit(chromeos_pstore_exit); | 134 | module_exit(chromeos_pstore_exit); |
| 140 | 135 | ||
| 141 | MODULE_DESCRIPTION("Chrome OS pstore module"); | 136 | MODULE_DESCRIPTION("ChromeOS pstore module"); |
| 142 | MODULE_LICENSE("GPL"); | 137 | MODULE_LICENSE("GPL v2"); |
diff --git a/drivers/platform/chrome/cros_ec_debugfs.c b/drivers/platform/chrome/cros_ec_debugfs.c index 6cacac53dfce..900c7073c46f 100644 --- a/drivers/platform/chrome/cros_ec_debugfs.c +++ b/drivers/platform/chrome/cros_ec_debugfs.c | |||
| @@ -1,21 +1,7 @@ | |||
| 1 | /* | 1 | // SPDX-License-Identifier: GPL-2.0+ |
| 2 | * cros_ec_debugfs - debug logs for Chrome OS EC | 2 | // Debug logs for the ChromeOS EC |
| 3 | * | 3 | // |
| 4 | * Copyright 2015 Google, Inc. | 4 | // Copyright (C) 2015 Google, Inc. |
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; either version 2 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | 5 | ||
| 20 | #include <linux/circ_buf.h> | 6 | #include <linux/circ_buf.h> |
| 21 | #include <linux/debugfs.h> | 7 | #include <linux/debugfs.h> |
diff --git a/drivers/platform/chrome/cros_ec_i2c.c b/drivers/platform/chrome/cros_ec_i2c.c index 9a009eaa4ada..61d75395f86d 100644 --- a/drivers/platform/chrome/cros_ec_i2c.c +++ b/drivers/platform/chrome/cros_ec_i2c.c | |||
| @@ -1,17 +1,7 @@ | |||
| 1 | /* | 1 | // SPDX-License-Identifier: GPL-2.0 |
| 2 | * ChromeOS EC multi-function device (I2C) | 2 | // I2C interface for ChromeOS Embedded Controller |
| 3 | * | 3 | // |
| 4 | * Copyright (C) 2012 Google, Inc | 4 | // Copyright (C) 2012 Google, Inc |
| 5 | * | ||
| 6 | * This software is licensed under the terms of the GNU General Public | ||
| 7 | * License version 2, as published by the Free Software Foundation, and | ||
| 8 | * may be copied, distributed, and modified under those terms. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | */ | ||
| 15 | 5 | ||
| 16 | #include <linux/acpi.h> | 6 | #include <linux/acpi.h> |
| 17 | #include <linux/delay.h> | 7 | #include <linux/delay.h> |
| @@ -372,5 +362,5 @@ static struct i2c_driver cros_ec_driver = { | |||
| 372 | 362 | ||
| 373 | module_i2c_driver(cros_ec_driver); | 363 | module_i2c_driver(cros_ec_driver); |
| 374 | 364 | ||
| 375 | MODULE_LICENSE("GPL"); | 365 | MODULE_LICENSE("GPL v2"); |
| 376 | MODULE_DESCRIPTION("ChromeOS EC multi function device"); | 366 | MODULE_DESCRIPTION("I2C interface for ChromeOS Embedded Controller"); |
diff --git a/drivers/platform/chrome/cros_ec_lightbar.c b/drivers/platform/chrome/cros_ec_lightbar.c index c3e4e6e5211d..d30a6650b0b5 100644 --- a/drivers/platform/chrome/cros_ec_lightbar.c +++ b/drivers/platform/chrome/cros_ec_lightbar.c | |||
| @@ -1,23 +1,7 @@ | |||
| 1 | /* | 1 | // SPDX-License-Identifier: GPL-2.0+ |
| 2 | * cros_ec_lightbar - expose the Chromebook Pixel lightbar to userspace | 2 | // Expose the Chromebook Pixel lightbar to userspace |
| 3 | * | 3 | // |
| 4 | * Copyright (C) 2014 Google, Inc. | 4 | // Copyright (C) 2014 Google, Inc. |
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; either version 2 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | |||
| 20 | #define pr_fmt(fmt) "cros_ec_lightbar: " fmt | ||
| 21 | 5 | ||
| 22 | #include <linux/ctype.h> | 6 | #include <linux/ctype.h> |
| 23 | #include <linux/delay.h> | 7 | #include <linux/delay.h> |
diff --git a/drivers/platform/chrome/cros_ec_lpc.c b/drivers/platform/chrome/cros_ec_lpc.c index 14684a56e40f..c9c240fbe7c6 100644 --- a/drivers/platform/chrome/cros_ec_lpc.c +++ b/drivers/platform/chrome/cros_ec_lpc.c | |||
| @@ -1,25 +1,15 @@ | |||
| 1 | /* | 1 | // SPDX-License-Identifier: GPL-2.0 |
| 2 | * cros_ec_lpc - LPC access to the Chrome OS Embedded Controller | 2 | // LPC interface for ChromeOS Embedded Controller |
| 3 | * | 3 | // |
| 4 | * Copyright (C) 2012-2015 Google, Inc | 4 | // Copyright (C) 2012-2015 Google, Inc |
| 5 | * | 5 | // |
| 6 | * This software is licensed under the terms of the GNU General Public | 6 | // This driver uses the ChromeOS EC byte-level message-based protocol for |
| 7 | * License version 2, as published by the Free Software Foundation, and | 7 | // communicating the keyboard state (which keys are pressed) from a keyboard EC |
| 8 | * may be copied, distributed, and modified under those terms. | 8 | // to the AP over some bus (such as i2c, lpc, spi). The EC does debouncing, |
| 9 | * | 9 | // but everything else (including deghosting) is done here. The main |
| 10 | * This program is distributed in the hope that it will be useful, | 10 | // motivation for this is to keep the EC firmware as simple as possible, since |
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 11 | // it cannot be easily upgraded and EC flash/IRAM space is relatively |
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 12 | // expensive. |
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * This driver uses the Chrome OS EC byte-level message-based protocol for | ||
| 16 | * communicating the keyboard state (which keys are pressed) from a keyboard EC | ||
| 17 | * to the AP over some bus (such as i2c, lpc, spi). The EC does debouncing, | ||
| 18 | * but everything else (including deghosting) is done here. The main | ||
| 19 | * motivation for this is to keep the EC firmware as simple as possible, since | ||
| 20 | * it cannot be easily upgraded and EC flash/IRAM space is relatively | ||
| 21 | * expensive. | ||
| 22 | */ | ||
| 23 | 13 | ||
| 24 | #include <linux/acpi.h> | 14 | #include <linux/acpi.h> |
| 25 | #include <linux/dmi.h> | 15 | #include <linux/dmi.h> |
diff --git a/drivers/platform/chrome/cros_ec_lpc_mec.c b/drivers/platform/chrome/cros_ec_lpc_mec.c index c4edfa83e493..d8890bafb55d 100644 --- a/drivers/platform/chrome/cros_ec_lpc_mec.c +++ b/drivers/platform/chrome/cros_ec_lpc_mec.c | |||
| @@ -1,29 +1,10 @@ | |||
| 1 | /* | 1 | // SPDX-License-Identifier: GPL-2.0 |
| 2 | * cros_ec_lpc_mec - LPC variant I/O for Microchip EC | 2 | // LPC variant I/O for Microchip EC |
| 3 | * | 3 | // |
| 4 | * Copyright (C) 2016 Google, Inc | 4 | // Copyright (C) 2016 Google, Inc |
| 5 | * | ||
| 6 | * This software is licensed under the terms of the GNU General Public | ||
| 7 | * License version 2, as published by the Free Software Foundation, and | ||
| 8 | * may be copied, distributed, and modified under those terms. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * This driver uses the Chrome OS EC byte-level message-based protocol for | ||
| 16 | * communicating the keyboard state (which keys are pressed) from a keyboard EC | ||
| 17 | * to the AP over some bus (such as i2c, lpc, spi). The EC does debouncing, | ||
| 18 | * but everything else (including deghosting) is done here. The main | ||
| 19 | * motivation for this is to keep the EC firmware as simple as possible, since | ||
| 20 | * it cannot be easily upgraded and EC flash/IRAM space is relatively | ||
| 21 | * expensive. | ||
| 22 | */ | ||
| 23 | 5 | ||
| 24 | #include <linux/delay.h> | 6 | #include <linux/delay.h> |
| 25 | #include <linux/io.h> | 7 | #include <linux/io.h> |
| 26 | #include <linux/mfd/cros_ec_commands.h> | ||
| 27 | #include <linux/mutex.h> | 8 | #include <linux/mutex.h> |
| 28 | #include <linux/types.h> | 9 | #include <linux/types.h> |
| 29 | 10 | ||
| @@ -34,6 +15,7 @@ | |||
| 34 | * EC mutex because memmap data may be accessed without it being held. | 15 | * EC mutex because memmap data may be accessed without it being held. |
| 35 | */ | 16 | */ |
| 36 | static struct mutex io_mutex; | 17 | static struct mutex io_mutex; |
| 18 | static u16 mec_emi_base, mec_emi_end; | ||
| 37 | 19 | ||
| 38 | /* | 20 | /* |
| 39 | * cros_ec_lpc_mec_emi_write_address | 21 | * cros_ec_lpc_mec_emi_write_address |
| @@ -46,10 +28,37 @@ static struct mutex io_mutex; | |||
| 46 | static void cros_ec_lpc_mec_emi_write_address(u16 addr, | 28 | static void cros_ec_lpc_mec_emi_write_address(u16 addr, |
| 47 | enum cros_ec_lpc_mec_emi_access_mode access_type) | 29 | enum cros_ec_lpc_mec_emi_access_mode access_type) |
| 48 | { | 30 | { |
| 49 | /* Address relative to start of EMI range */ | 31 | outb((addr & 0xfc) | access_type, MEC_EMI_EC_ADDRESS_B0(mec_emi_base)); |
| 50 | addr -= MEC_EMI_RANGE_START; | 32 | outb((addr >> 8) & 0x7f, MEC_EMI_EC_ADDRESS_B1(mec_emi_base)); |
| 51 | outb((addr & 0xfc) | access_type, MEC_EMI_EC_ADDRESS_B0); | 33 | } |
| 52 | outb((addr >> 8) & 0x7f, MEC_EMI_EC_ADDRESS_B1); | 34 | |
| 35 | /** | ||
| 36 | * cros_ec_lpc_mec_in_range() - Determine if addresses are in MEC EMI range. | ||
| 37 | * | ||
| 38 | * @offset: Address offset | ||
| 39 | * @length: Number of bytes to check | ||
| 40 | * | ||
| 41 | * Return: 1 if in range, 0 if not, and -EINVAL on failure | ||
| 42 | * such as the mec range not being initialized | ||
| 43 | */ | ||
| 44 | int cros_ec_lpc_mec_in_range(unsigned int offset, unsigned int length) | ||
| 45 | { | ||
| 46 | if (length == 0) | ||
| 47 | return -EINVAL; | ||
| 48 | |||
| 49 | if (WARN_ON(mec_emi_base == 0 || mec_emi_end == 0)) | ||
| 50 | return -EINVAL; | ||
| 51 | |||
| 52 | if (offset >= mec_emi_base && offset < mec_emi_end) { | ||
| 53 | if (WARN_ON(offset + length - 1 >= mec_emi_end)) | ||
| 54 | return -EINVAL; | ||
| 55 | return 1; | ||
| 56 | } | ||
| 57 | |||
| 58 | if (WARN_ON(offset + length > mec_emi_base && offset < mec_emi_end)) | ||
| 59 | return -EINVAL; | ||
| 60 | |||
| 61 | return 0; | ||
| 53 | } | 62 | } |
| 54 | 63 | ||
| 55 | /* | 64 | /* |
| @@ -71,6 +80,11 @@ u8 cros_ec_lpc_io_bytes_mec(enum cros_ec_lpc_mec_io_type io_type, | |||
| 71 | u8 sum = 0; | 80 | u8 sum = 0; |
| 72 | enum cros_ec_lpc_mec_emi_access_mode access, new_access; | 81 | enum cros_ec_lpc_mec_emi_access_mode access, new_access; |
| 73 | 82 | ||
| 83 | /* Return checksum of 0 if window is not initialized */ | ||
| 84 | WARN_ON(mec_emi_base == 0 || mec_emi_end == 0); | ||
| 85 | if (mec_emi_base == 0 || mec_emi_end == 0) | ||
| 86 | return 0; | ||
| 87 | |||
| 74 | /* | 88 | /* |
| 75 | * Long access cannot be used on misaligned data since reading B0 loads | 89 | * Long access cannot be used on misaligned data since reading B0 loads |
| 76 | * the data register and writing B3 flushes. | 90 | * 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, | |||
| 86 | cros_ec_lpc_mec_emi_write_address(offset, access); | 100 | cros_ec_lpc_mec_emi_write_address(offset, access); |
| 87 | 101 | ||
| 88 | /* Skip bytes in case of misaligned offset */ | 102 | /* Skip bytes in case of misaligned offset */ |
| 89 | io_addr = MEC_EMI_EC_DATA_B0 + (offset & 0x3); | 103 | io_addr = MEC_EMI_EC_DATA_B0(mec_emi_base) + (offset & 0x3); |
| 90 | while (i < length) { | 104 | while (i < length) { |
| 91 | while (io_addr <= MEC_EMI_EC_DATA_B3) { | 105 | while (io_addr <= MEC_EMI_EC_DATA_B3(mec_emi_base)) { |
| 92 | if (io_type == MEC_IO_READ) | 106 | if (io_type == MEC_IO_READ) |
| 93 | buf[i] = inb(io_addr++); | 107 | buf[i] = inb(io_addr++); |
| 94 | else | 108 | else |
| @@ -118,7 +132,7 @@ u8 cros_ec_lpc_io_bytes_mec(enum cros_ec_lpc_mec_io_type io_type, | |||
| 118 | } | 132 | } |
| 119 | 133 | ||
| 120 | /* Access [B0, B3] on each loop pass */ | 134 | /* Access [B0, B3] on each loop pass */ |
| 121 | io_addr = MEC_EMI_EC_DATA_B0; | 135 | io_addr = MEC_EMI_EC_DATA_B0(mec_emi_base); |
| 122 | } | 136 | } |
| 123 | 137 | ||
| 124 | done: | 138 | done: |
| @@ -128,9 +142,11 @@ done: | |||
| 128 | } | 142 | } |
| 129 | EXPORT_SYMBOL(cros_ec_lpc_io_bytes_mec); | 143 | EXPORT_SYMBOL(cros_ec_lpc_io_bytes_mec); |
| 130 | 144 | ||
| 131 | void cros_ec_lpc_mec_init(void) | 145 | void cros_ec_lpc_mec_init(unsigned int base, unsigned int end) |
| 132 | { | 146 | { |
| 133 | mutex_init(&io_mutex); | 147 | mutex_init(&io_mutex); |
| 148 | mec_emi_base = base; | ||
| 149 | mec_emi_end = end; | ||
| 134 | } | 150 | } |
| 135 | EXPORT_SYMBOL(cros_ec_lpc_mec_init); | 151 | EXPORT_SYMBOL(cros_ec_lpc_mec_init); |
| 136 | 152 | ||
diff --git a/drivers/platform/chrome/cros_ec_lpc_mec.h b/drivers/platform/chrome/cros_ec_lpc_mec.h index 105068c0e919..aa1018f6b0f2 100644 --- a/drivers/platform/chrome/cros_ec_lpc_mec.h +++ b/drivers/platform/chrome/cros_ec_lpc_mec.h | |||
| @@ -1,31 +1,13 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
| 1 | /* | 2 | /* |
| 2 | * cros_ec_lpc_mec - LPC variant I/O for Microchip EC | 3 | * LPC variant I/O for Microchip EC |
| 3 | * | 4 | * |
| 4 | * Copyright (C) 2016 Google, Inc | 5 | * Copyright (C) 2016 Google, Inc |
| 5 | * | ||
| 6 | * This software is licensed under the terms of the GNU General Public | ||
| 7 | * License version 2, as published by the Free Software Foundation, and | ||
| 8 | * may be copied, distributed, and modified under those terms. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * This driver uses the Chrome OS EC byte-level message-based protocol for | ||
| 16 | * communicating the keyboard state (which keys are pressed) from a keyboard EC | ||
| 17 | * to the AP over some bus (such as i2c, lpc, spi). The EC does debouncing, | ||
| 18 | * but everything else (including deghosting) is done here. The main | ||
| 19 | * motivation for this is to keep the EC firmware as simple as possible, since | ||
| 20 | * it cannot be easily upgraded and EC flash/IRAM space is relatively | ||
| 21 | * expensive. | ||
| 22 | */ | 6 | */ |
| 23 | 7 | ||
| 24 | #ifndef __CROS_EC_LPC_MEC_H | 8 | #ifndef __CROS_EC_LPC_MEC_H |
| 25 | #define __CROS_EC_LPC_MEC_H | 9 | #define __CROS_EC_LPC_MEC_H |
| 26 | 10 | ||
| 27 | #include <linux/mfd/cros_ec_commands.h> | ||
| 28 | |||
| 29 | enum cros_ec_lpc_mec_emi_access_mode { | 11 | enum cros_ec_lpc_mec_emi_access_mode { |
| 30 | /* 8-bit access */ | 12 | /* 8-bit access */ |
| 31 | ACCESS_TYPE_BYTE = 0x0, | 13 | ACCESS_TYPE_BYTE = 0x0, |
| @@ -45,27 +27,23 @@ enum cros_ec_lpc_mec_io_type { | |||
| 45 | MEC_IO_WRITE, | 27 | MEC_IO_WRITE, |
| 46 | }; | 28 | }; |
| 47 | 29 | ||
| 48 | /* Access IO ranges 0x800 thru 0x9ff using EMI interface instead of LPC */ | ||
| 49 | #define MEC_EMI_RANGE_START EC_HOST_CMD_REGION0 | ||
| 50 | #define MEC_EMI_RANGE_END (EC_LPC_ADDR_MEMMAP + EC_MEMMAP_SIZE) | ||
| 51 | |||
| 52 | /* EMI registers are relative to base */ | 30 | /* EMI registers are relative to base */ |
| 53 | #define MEC_EMI_BASE 0x800 | 31 | #define MEC_EMI_HOST_TO_EC(MEC_EMI_BASE) ((MEC_EMI_BASE) + 0) |
| 54 | #define MEC_EMI_HOST_TO_EC (MEC_EMI_BASE + 0) | 32 | #define MEC_EMI_EC_TO_HOST(MEC_EMI_BASE) ((MEC_EMI_BASE) + 1) |
| 55 | #define MEC_EMI_EC_TO_HOST (MEC_EMI_BASE + 1) | 33 | #define MEC_EMI_EC_ADDRESS_B0(MEC_EMI_BASE) ((MEC_EMI_BASE) + 2) |
| 56 | #define MEC_EMI_EC_ADDRESS_B0 (MEC_EMI_BASE + 2) | 34 | #define MEC_EMI_EC_ADDRESS_B1(MEC_EMI_BASE) ((MEC_EMI_BASE) + 3) |
| 57 | #define MEC_EMI_EC_ADDRESS_B1 (MEC_EMI_BASE + 3) | 35 | #define MEC_EMI_EC_DATA_B0(MEC_EMI_BASE) ((MEC_EMI_BASE) + 4) |
| 58 | #define MEC_EMI_EC_DATA_B0 (MEC_EMI_BASE + 4) | 36 | #define MEC_EMI_EC_DATA_B1(MEC_EMI_BASE) ((MEC_EMI_BASE) + 5) |
| 59 | #define MEC_EMI_EC_DATA_B1 (MEC_EMI_BASE + 5) | 37 | #define MEC_EMI_EC_DATA_B2(MEC_EMI_BASE) ((MEC_EMI_BASE) + 6) |
| 60 | #define MEC_EMI_EC_DATA_B2 (MEC_EMI_BASE + 6) | 38 | #define MEC_EMI_EC_DATA_B3(MEC_EMI_BASE) ((MEC_EMI_BASE) + 7) |
| 61 | #define MEC_EMI_EC_DATA_B3 (MEC_EMI_BASE + 7) | ||
| 62 | 39 | ||
| 63 | /* | 40 | /** |
| 64 | * cros_ec_lpc_mec_init | 41 | * cros_ec_lpc_mec_init() - Initialize MEC I/O. |
| 65 | * | 42 | * |
| 66 | * Initialize MEC I/O. | 43 | * @base: MEC EMI Base address |
| 44 | * @end: MEC EMI End address | ||
| 67 | */ | 45 | */ |
| 68 | void cros_ec_lpc_mec_init(void); | 46 | void cros_ec_lpc_mec_init(unsigned int base, unsigned int end); |
| 69 | 47 | ||
| 70 | /* | 48 | /* |
| 71 | * cros_ec_lpc_mec_destroy | 49 | * cros_ec_lpc_mec_destroy |
| @@ -75,6 +53,17 @@ void cros_ec_lpc_mec_init(void); | |||
| 75 | void cros_ec_lpc_mec_destroy(void); | 53 | void cros_ec_lpc_mec_destroy(void); |
| 76 | 54 | ||
| 77 | /** | 55 | /** |
| 56 | * cros_ec_lpc_mec_in_range() - Determine if addresses are in MEC EMI range. | ||
| 57 | * | ||
| 58 | * @offset: Address offset | ||
| 59 | * @length: Number of bytes to check | ||
| 60 | * | ||
| 61 | * Return: 1 if in range, 0 if not, and -EINVAL on failure | ||
| 62 | * such as the mec range not being initialized | ||
| 63 | */ | ||
| 64 | int cros_ec_lpc_mec_in_range(unsigned int offset, unsigned int length); | ||
| 65 | |||
| 66 | /** | ||
| 78 | * cros_ec_lpc_io_bytes_mec - Read / write bytes to MEC EMI port | 67 | * cros_ec_lpc_io_bytes_mec - Read / write bytes to MEC EMI port |
| 79 | * | 68 | * |
| 80 | * @io_type: MEC_IO_READ or MEC_IO_WRITE, depending on request | 69 | * @io_type: MEC_IO_READ or MEC_IO_WRITE, depending on request |
diff --git a/drivers/platform/chrome/cros_ec_lpc_reg.c b/drivers/platform/chrome/cros_ec_lpc_reg.c index fc23d535c404..0f5cd0ac8b49 100644 --- a/drivers/platform/chrome/cros_ec_lpc_reg.c +++ b/drivers/platform/chrome/cros_ec_lpc_reg.c | |||
| @@ -1,25 +1,7 @@ | |||
| 1 | /* | 1 | // SPDX-License-Identifier: GPL-2.0 |
| 2 | * cros_ec_lpc_reg - LPC access to the Chrome OS Embedded Controller | 2 | // LPC interface for ChromeOS Embedded Controller |
| 3 | * | 3 | // |
| 4 | * Copyright (C) 2016 Google, Inc | 4 | // Copyright (C) 2016 Google, Inc |
| 5 | * | ||
| 6 | * This software is licensed under the terms of the GNU General Public | ||
| 7 | * License version 2, as published by the Free Software Foundation, and | ||
| 8 | * may be copied, distributed, and modified under those terms. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * This driver uses the Chrome OS EC byte-level message-based protocol for | ||
| 16 | * communicating the keyboard state (which keys are pressed) from a keyboard EC | ||
| 17 | * to the AP over some bus (such as i2c, lpc, spi). The EC does debouncing, | ||
| 18 | * but everything else (including deghosting) is done here. The main | ||
| 19 | * motivation for this is to keep the EC firmware as simple as possible, since | ||
| 20 | * it cannot be easily upgraded and EC flash/IRAM space is relatively | ||
| 21 | * expensive. | ||
| 22 | */ | ||
| 23 | 5 | ||
| 24 | #include <linux/io.h> | 6 | #include <linux/io.h> |
| 25 | #include <linux/mfd/cros_ec.h> | 7 | #include <linux/mfd/cros_ec.h> |
| @@ -59,51 +41,36 @@ static u8 lpc_write_bytes(unsigned int offset, unsigned int length, u8 *msg) | |||
| 59 | 41 | ||
| 60 | u8 cros_ec_lpc_read_bytes(unsigned int offset, unsigned int length, u8 *dest) | 42 | u8 cros_ec_lpc_read_bytes(unsigned int offset, unsigned int length, u8 *dest) |
| 61 | { | 43 | { |
| 62 | if (length == 0) | 44 | int in_range = cros_ec_lpc_mec_in_range(offset, length); |
| 63 | return 0; | ||
| 64 | |||
| 65 | /* Access desired range through EMI interface */ | ||
| 66 | if (offset >= MEC_EMI_RANGE_START && offset <= MEC_EMI_RANGE_END) { | ||
| 67 | /* Ensure we don't straddle EMI region */ | ||
| 68 | if (WARN_ON(offset + length - 1 > MEC_EMI_RANGE_END)) | ||
| 69 | return 0; | ||
| 70 | 45 | ||
| 71 | return cros_ec_lpc_io_bytes_mec(MEC_IO_READ, offset, length, | 46 | if (in_range < 0) |
| 72 | dest); | ||
| 73 | } | ||
| 74 | |||
| 75 | if (WARN_ON(offset + length > MEC_EMI_RANGE_START && | ||
| 76 | offset < MEC_EMI_RANGE_START)) | ||
| 77 | return 0; | 47 | return 0; |
| 78 | 48 | ||
| 79 | return lpc_read_bytes(offset, length, dest); | 49 | return in_range ? |
| 50 | cros_ec_lpc_io_bytes_mec(MEC_IO_READ, | ||
| 51 | offset - EC_HOST_CMD_REGION0, | ||
| 52 | length, dest) : | ||
| 53 | lpc_read_bytes(offset, length, dest); | ||
| 80 | } | 54 | } |
| 81 | 55 | ||
| 82 | u8 cros_ec_lpc_write_bytes(unsigned int offset, unsigned int length, u8 *msg) | 56 | u8 cros_ec_lpc_write_bytes(unsigned int offset, unsigned int length, u8 *msg) |
| 83 | { | 57 | { |
| 84 | if (length == 0) | 58 | int in_range = cros_ec_lpc_mec_in_range(offset, length); |
| 85 | return 0; | ||
| 86 | |||
| 87 | /* Access desired range through EMI interface */ | ||
| 88 | if (offset >= MEC_EMI_RANGE_START && offset <= MEC_EMI_RANGE_END) { | ||
| 89 | /* Ensure we don't straddle EMI region */ | ||
| 90 | if (WARN_ON(offset + length - 1 > MEC_EMI_RANGE_END)) | ||
| 91 | return 0; | ||
| 92 | 59 | ||
| 93 | return cros_ec_lpc_io_bytes_mec(MEC_IO_WRITE, offset, length, | 60 | if (in_range < 0) |
| 94 | msg); | ||
| 95 | } | ||
| 96 | |||
| 97 | if (WARN_ON(offset + length > MEC_EMI_RANGE_START && | ||
| 98 | offset < MEC_EMI_RANGE_START)) | ||
| 99 | return 0; | 61 | return 0; |
| 100 | 62 | ||
| 101 | return lpc_write_bytes(offset, length, msg); | 63 | return in_range ? |
| 64 | cros_ec_lpc_io_bytes_mec(MEC_IO_WRITE, | ||
| 65 | offset - EC_HOST_CMD_REGION0, | ||
| 66 | length, msg) : | ||
| 67 | lpc_write_bytes(offset, length, msg); | ||
| 102 | } | 68 | } |
| 103 | 69 | ||
| 104 | void cros_ec_lpc_reg_init(void) | 70 | void cros_ec_lpc_reg_init(void) |
| 105 | { | 71 | { |
| 106 | cros_ec_lpc_mec_init(); | 72 | cros_ec_lpc_mec_init(EC_HOST_CMD_REGION0, |
| 73 | EC_LPC_ADDR_MEMMAP + EC_MEMMAP_SIZE); | ||
| 107 | } | 74 | } |
| 108 | 75 | ||
| 109 | void cros_ec_lpc_reg_destroy(void) | 76 | void cros_ec_lpc_reg_destroy(void) |
diff --git a/drivers/platform/chrome/cros_ec_lpc_reg.h b/drivers/platform/chrome/cros_ec_lpc_reg.h index 1c12c38b306a..416fd2572182 100644 --- a/drivers/platform/chrome/cros_ec_lpc_reg.h +++ b/drivers/platform/chrome/cros_ec_lpc_reg.h | |||
| @@ -1,24 +1,8 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
| 1 | /* | 2 | /* |
| 2 | * cros_ec_lpc_reg - LPC access to the Chrome OS Embedded Controller | 3 | * LPC interface for ChromeOS Embedded Controller |
| 3 | * | 4 | * |
| 4 | * Copyright (C) 2016 Google, Inc | 5 | * Copyright (C) 2016 Google, Inc |
| 5 | * | ||
| 6 | * This software is licensed under the terms of the GNU General Public | ||
| 7 | * License version 2, as published by the Free Software Foundation, and | ||
| 8 | * may be copied, distributed, and modified under those terms. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * This driver uses the Chrome OS EC byte-level message-based protocol for | ||
| 16 | * communicating the keyboard state (which keys are pressed) from a keyboard EC | ||
| 17 | * to the AP over some bus (such as i2c, lpc, spi). The EC does debouncing, | ||
| 18 | * but everything else (including deghosting) is done here. The main | ||
| 19 | * motivation for this is to keep the EC firmware as simple as possible, since | ||
| 20 | * it cannot be easily upgraded and EC flash/IRAM space is relatively | ||
| 21 | * expensive. | ||
| 22 | */ | 6 | */ |
| 23 | 7 | ||
| 24 | #ifndef __CROS_EC_LPC_REG_H | 8 | #ifndef __CROS_EC_LPC_REG_H |
diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c index cc7baf0ecb3c..97a068dff192 100644 --- a/drivers/platform/chrome/cros_ec_proto.c +++ b/drivers/platform/chrome/cros_ec_proto.c | |||
| @@ -1,18 +1,7 @@ | |||
| 1 | /* | 1 | // SPDX-License-Identifier: GPL-2.0 |
| 2 | * ChromeOS EC communication protocol helper functions | 2 | // ChromeOS EC communication protocol helper functions |
| 3 | * | 3 | // |
| 4 | * Copyright (C) 2015 Google, Inc | 4 | // Copyright (C) 2015 Google, Inc |
| 5 | * | ||
| 6 | * This software is licensed under the terms of the GNU General Public | ||
| 7 | * License version 2, as published by the Free Software Foundation, and | ||
| 8 | * may be copied, distributed, and modified under those terms. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | */ | ||
| 16 | 5 | ||
| 17 | #include <linux/mfd/cros_ec.h> | 6 | #include <linux/mfd/cros_ec.h> |
| 18 | #include <linux/delay.h> | 7 | #include <linux/delay.h> |
diff --git a/drivers/platform/chrome/cros_ec_spi.c b/drivers/platform/chrome/cros_ec_spi.c index 6cfbc2835beb..ffc38f9d4829 100644 --- a/drivers/platform/chrome/cros_ec_spi.c +++ b/drivers/platform/chrome/cros_ec_spi.c | |||
| @@ -1,17 +1,7 @@ | |||
| 1 | /* | 1 | // SPDX-License-Identifier: GPL-2.0 |
| 2 | * ChromeOS EC multi-function device (SPI) | 2 | // SPI interface for ChromeOS Embedded Controller |
| 3 | * | 3 | // |
| 4 | * Copyright (C) 2012 Google, Inc | 4 | // Copyright (C) 2012 Google, Inc |
| 5 | * | ||
| 6 | * This software is licensed under the terms of the GNU General Public | ||
| 7 | * License version 2, as published by the Free Software Foundation, and | ||
| 8 | * may be copied, distributed, and modified under those terms. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | */ | ||
| 15 | 5 | ||
| 16 | #include <linux/delay.h> | 6 | #include <linux/delay.h> |
| 17 | #include <linux/kernel.h> | 7 | #include <linux/kernel.h> |
| @@ -729,4 +719,4 @@ static struct spi_driver cros_ec_driver_spi = { | |||
| 729 | module_spi_driver(cros_ec_driver_spi); | 719 | module_spi_driver(cros_ec_driver_spi); |
| 730 | 720 | ||
| 731 | MODULE_LICENSE("GPL v2"); | 721 | MODULE_LICENSE("GPL v2"); |
| 732 | MODULE_DESCRIPTION("ChromeOS EC multi function device (SPI)"); | 722 | MODULE_DESCRIPTION("SPI interface for ChromeOS Embedded Controller"); |
diff --git a/drivers/platform/chrome/cros_ec_sysfs.c b/drivers/platform/chrome/cros_ec_sysfs.c index 0ff5aa30c070..fe0b7614ae1b 100644 --- a/drivers/platform/chrome/cros_ec_sysfs.c +++ b/drivers/platform/chrome/cros_ec_sysfs.c | |||
| @@ -1,23 +1,7 @@ | |||
| 1 | /* | 1 | // SPDX-License-Identifier: GPL-2.0+ |
| 2 | * cros_ec_sysfs - expose the Chrome OS EC through sysfs | 2 | // Expose the ChromeOS EC through sysfs |
| 3 | * | 3 | // |
| 4 | * Copyright (C) 2014 Google, Inc. | 4 | // Copyright (C) 2014 Google, Inc. |
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; either version 2 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | |||
| 20 | #define pr_fmt(fmt) "cros_ec_sysfs: " fmt | ||
| 21 | 5 | ||
| 22 | #include <linux/ctype.h> | 6 | #include <linux/ctype.h> |
| 23 | #include <linux/delay.h> | 7 | #include <linux/delay.h> |
| @@ -389,5 +373,5 @@ static struct platform_driver cros_ec_sysfs_driver = { | |||
| 389 | module_platform_driver(cros_ec_sysfs_driver); | 373 | module_platform_driver(cros_ec_sysfs_driver); |
| 390 | 374 | ||
| 391 | MODULE_LICENSE("GPL"); | 375 | MODULE_LICENSE("GPL"); |
| 392 | MODULE_DESCRIPTION("ChromeOS EC control driver"); | 376 | MODULE_DESCRIPTION("Expose the ChromeOS EC through sysfs"); |
| 393 | MODULE_ALIAS("platform:" DRV_NAME); | 377 | MODULE_ALIAS("platform:" DRV_NAME); |
diff --git a/drivers/platform/chrome/cros_ec_vbc.c b/drivers/platform/chrome/cros_ec_vbc.c index af9bfe6f385c..8392a1ec33a7 100644 --- a/drivers/platform/chrome/cros_ec_vbc.c +++ b/drivers/platform/chrome/cros_ec_vbc.c | |||
| @@ -1,22 +1,8 @@ | |||
| 1 | /* | 1 | // SPDX-License-Identifier: GPL-2.0+ |
| 2 | * cros_ec_vbc - Expose the vboot context nvram to userspace | 2 | // Expose the vboot context nvram to userspace |
| 3 | * | 3 | // |
| 4 | * Copyright (C) 2015 Collabora Ltd. | 4 | // Copyright (C) 2012 Google, Inc. |
| 5 | * | 5 | // Copyright (C) 2015 Collabora Ltd. |
| 6 | * based on vendor driver, | ||
| 7 | * | ||
| 8 | * Copyright (C) 2012 The Chromium OS Authors | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or modify | ||
| 11 | * it under the terms of the GNU General Public License as published by | ||
| 12 | * the Free Software Foundation; either version 2 of the License, or | ||
| 13 | * (at your option) any later version. | ||
| 14 | * | ||
| 15 | * This program is distributed in the hope that it will be useful, | ||
| 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 18 | * GNU General Public License for more details. | ||
| 19 | */ | ||
| 20 | 6 | ||
| 21 | #include <linux/of.h> | 7 | #include <linux/of.h> |
| 22 | #include <linux/platform_device.h> | 8 | #include <linux/platform_device.h> |
diff --git a/drivers/platform/chrome/cros_kbd_led_backlight.c b/drivers/platform/chrome/cros_kbd_led_backlight.c index ca3e4da852b4..aa409f0201fb 100644 --- a/drivers/platform/chrome/cros_kbd_led_backlight.c +++ b/drivers/platform/chrome/cros_kbd_led_backlight.c | |||
| @@ -1,18 +1,7 @@ | |||
| 1 | /* | 1 | // SPDX-License-Identifier: GPL-2.0+ |
| 2 | * Keyboard backlight LED driver for Chrome OS. | 2 | // Keyboard backlight LED driver for ChromeOS |
| 3 | * | 3 | // |
| 4 | * Copyright (C) 2012 Google, Inc. | 4 | // Copyright (C) 2012 Google, Inc. |
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; either version 2 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | */ | ||
| 16 | 5 | ||
| 17 | #include <linux/acpi.h> | 6 | #include <linux/acpi.h> |
| 18 | #include <linux/leds.h> | 7 | #include <linux/leds.h> |
diff --git a/drivers/platform/chrome/wilco_ec/Kconfig b/drivers/platform/chrome/wilco_ec/Kconfig new file mode 100644 index 000000000000..e09e4cebe9b4 --- /dev/null +++ b/drivers/platform/chrome/wilco_ec/Kconfig | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | config WILCO_EC | ||
| 2 | tristate "ChromeOS Wilco Embedded Controller" | ||
| 3 | depends on ACPI && X86 && CROS_EC_LPC && CROS_EC_LPC_MEC | ||
| 4 | help | ||
| 5 | If you say Y here, you get support for talking to the ChromeOS | ||
| 6 | Wilco EC over an eSPI bus. This uses a simple byte-level protocol | ||
| 7 | with a checksum. | ||
| 8 | |||
| 9 | To compile this driver as a module, choose M here: the | ||
| 10 | module will be called wilco_ec. | ||
| 11 | |||
| 12 | config WILCO_EC_DEBUGFS | ||
| 13 | tristate "Enable raw access to EC via debugfs" | ||
| 14 | depends on WILCO_EC | ||
| 15 | help | ||
| 16 | If you say Y here, you get support for sending raw commands to | ||
| 17 | the Wilco EC via debugfs. These commands do not do any byte | ||
| 18 | manipulation and allow for testing arbitrary commands. This | ||
| 19 | interface is intended for debug only and will not be present | ||
| 20 | on production devices. | ||
diff --git a/drivers/platform/chrome/wilco_ec/Makefile b/drivers/platform/chrome/wilco_ec/Makefile new file mode 100644 index 000000000000..063e7fb4ea17 --- /dev/null +++ b/drivers/platform/chrome/wilco_ec/Makefile | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0 | ||
| 2 | |||
| 3 | wilco_ec-objs := core.o mailbox.o | ||
| 4 | obj-$(CONFIG_WILCO_EC) += wilco_ec.o | ||
| 5 | wilco_ec_debugfs-objs := debugfs.o | ||
| 6 | 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 index 000000000000..05e1e2be1c91 --- /dev/null +++ b/drivers/platform/chrome/wilco_ec/core.c | |||
| @@ -0,0 +1,136 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * Core driver for Wilco Embedded Controller | ||
| 4 | * | ||
| 5 | * Copyright 2018 Google LLC | ||
| 6 | * | ||
| 7 | * This is the entry point for the drivers that control the Wilco EC. | ||
| 8 | * This driver is responsible for several tasks: | ||
| 9 | * - Initialize the register interface that is used by wilco_ec_mailbox() | ||
| 10 | * - Create a platform device which is picked up by the debugfs driver | ||
| 11 | * - Create a platform device which is picked up by the RTC driver | ||
| 12 | */ | ||
| 13 | |||
| 14 | #include <linux/acpi.h> | ||
| 15 | #include <linux/device.h> | ||
| 16 | #include <linux/ioport.h> | ||
| 17 | #include <linux/module.h> | ||
| 18 | #include <linux/platform_data/wilco-ec.h> | ||
| 19 | #include <linux/platform_device.h> | ||
| 20 | |||
| 21 | #include "../cros_ec_lpc_mec.h" | ||
| 22 | |||
| 23 | #define DRV_NAME "wilco-ec" | ||
| 24 | |||
| 25 | static struct resource *wilco_get_resource(struct platform_device *pdev, | ||
| 26 | int index) | ||
| 27 | { | ||
| 28 | struct device *dev = &pdev->dev; | ||
| 29 | struct resource *res; | ||
| 30 | |||
| 31 | res = platform_get_resource(pdev, IORESOURCE_IO, index); | ||
| 32 | if (!res) { | ||
| 33 | dev_dbg(dev, "Couldn't find IO resource %d\n", index); | ||
| 34 | return res; | ||
| 35 | } | ||
| 36 | |||
| 37 | return devm_request_region(dev, res->start, resource_size(res), | ||
| 38 | dev_name(dev)); | ||
| 39 | } | ||
| 40 | |||
| 41 | static int wilco_ec_probe(struct platform_device *pdev) | ||
| 42 | { | ||
| 43 | struct device *dev = &pdev->dev; | ||
| 44 | struct wilco_ec_device *ec; | ||
| 45 | int ret; | ||
| 46 | |||
| 47 | ec = devm_kzalloc(dev, sizeof(*ec), GFP_KERNEL); | ||
| 48 | if (!ec) | ||
| 49 | return -ENOMEM; | ||
| 50 | |||
| 51 | platform_set_drvdata(pdev, ec); | ||
| 52 | ec->dev = dev; | ||
| 53 | mutex_init(&ec->mailbox_lock); | ||
| 54 | |||
| 55 | /* Largest data buffer size requirement is extended data response */ | ||
| 56 | ec->data_size = sizeof(struct wilco_ec_response) + | ||
| 57 | EC_MAILBOX_DATA_SIZE_EXTENDED; | ||
| 58 | ec->data_buffer = devm_kzalloc(dev, ec->data_size, GFP_KERNEL); | ||
| 59 | if (!ec->data_buffer) | ||
| 60 | return -ENOMEM; | ||
| 61 | |||
| 62 | /* Prepare access to IO regions provided by ACPI */ | ||
| 63 | ec->io_data = wilco_get_resource(pdev, 0); /* Host Data */ | ||
| 64 | ec->io_command = wilco_get_resource(pdev, 1); /* Host Command */ | ||
| 65 | ec->io_packet = wilco_get_resource(pdev, 2); /* MEC EMI */ | ||
| 66 | if (!ec->io_data || !ec->io_command || !ec->io_packet) | ||
| 67 | return -ENODEV; | ||
| 68 | |||
| 69 | /* Initialize cros_ec register interface for communication */ | ||
| 70 | cros_ec_lpc_mec_init(ec->io_packet->start, | ||
| 71 | ec->io_packet->start + EC_MAILBOX_DATA_SIZE); | ||
| 72 | |||
| 73 | /* | ||
| 74 | * Register a child device that will be found by the debugfs driver. | ||
| 75 | * Ignore failure. | ||
| 76 | */ | ||
| 77 | ec->debugfs_pdev = platform_device_register_data(dev, | ||
| 78 | "wilco-ec-debugfs", | ||
| 79 | PLATFORM_DEVID_AUTO, | ||
| 80 | NULL, 0); | ||
| 81 | |||
| 82 | /* Register a child device that will be found by the RTC driver. */ | ||
| 83 | ec->rtc_pdev = platform_device_register_data(dev, "rtc-wilco-ec", | ||
| 84 | PLATFORM_DEVID_AUTO, | ||
| 85 | NULL, 0); | ||
| 86 | if (IS_ERR(ec->rtc_pdev)) { | ||
| 87 | dev_err(dev, "Failed to create RTC platform device\n"); | ||
| 88 | ret = PTR_ERR(ec->rtc_pdev); | ||
| 89 | goto unregister_debugfs; | ||
| 90 | } | ||
| 91 | |||
| 92 | return 0; | ||
| 93 | |||
| 94 | unregister_debugfs: | ||
| 95 | if (ec->debugfs_pdev) | ||
| 96 | platform_device_unregister(ec->debugfs_pdev); | ||
| 97 | cros_ec_lpc_mec_destroy(); | ||
| 98 | return ret; | ||
| 99 | } | ||
| 100 | |||
| 101 | static int wilco_ec_remove(struct platform_device *pdev) | ||
| 102 | { | ||
| 103 | struct wilco_ec_device *ec = platform_get_drvdata(pdev); | ||
| 104 | |||
| 105 | platform_device_unregister(ec->rtc_pdev); | ||
| 106 | if (ec->debugfs_pdev) | ||
| 107 | platform_device_unregister(ec->debugfs_pdev); | ||
| 108 | |||
| 109 | /* Teardown cros_ec interface */ | ||
| 110 | cros_ec_lpc_mec_destroy(); | ||
| 111 | |||
| 112 | return 0; | ||
| 113 | } | ||
| 114 | |||
| 115 | static const struct acpi_device_id wilco_ec_acpi_device_ids[] = { | ||
| 116 | { "GOOG000C", 0 }, | ||
| 117 | { } | ||
| 118 | }; | ||
| 119 | MODULE_DEVICE_TABLE(acpi, wilco_ec_acpi_device_ids); | ||
| 120 | |||
| 121 | static struct platform_driver wilco_ec_driver = { | ||
| 122 | .driver = { | ||
| 123 | .name = DRV_NAME, | ||
| 124 | .acpi_match_table = wilco_ec_acpi_device_ids, | ||
| 125 | }, | ||
| 126 | .probe = wilco_ec_probe, | ||
| 127 | .remove = wilco_ec_remove, | ||
| 128 | }; | ||
| 129 | |||
| 130 | module_platform_driver(wilco_ec_driver); | ||
| 131 | |||
| 132 | MODULE_AUTHOR("Nick Crews <ncrews@chromium.org>"); | ||
| 133 | MODULE_AUTHOR("Duncan Laurie <dlaurie@chromium.org>"); | ||
| 134 | MODULE_LICENSE("GPL v2"); | ||
| 135 | MODULE_DESCRIPTION("ChromeOS Wilco Embedded Controller driver"); | ||
| 136 | 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 index 000000000000..c090db2cd5be --- /dev/null +++ b/drivers/platform/chrome/wilco_ec/debugfs.c | |||
| @@ -0,0 +1,238 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * debugfs attributes for Wilco EC | ||
| 4 | * | ||
| 5 | * Copyright 2019 Google LLC | ||
| 6 | * | ||
| 7 | * There is only one attribute used for debugging, called raw. | ||
| 8 | * You can write a hexadecimal sentence to raw, and that series of bytes | ||
| 9 | * will be sent to the EC. Then, you can read the bytes of response | ||
| 10 | * by reading from raw. | ||
| 11 | * | ||
| 12 | * For writing: | ||
| 13 | * Bytes 0-1 indicate the message type: | ||
| 14 | * 00 F0 = Execute Legacy Command | ||
| 15 | * 00 F2 = Read/Write NVRAM Property | ||
| 16 | * Byte 2 provides the command code | ||
| 17 | * Bytes 3+ consist of the data passed in the request | ||
| 18 | * | ||
| 19 | * When referencing the EC interface spec, byte 2 corresponds to MBOX[0], | ||
| 20 | * byte 3 corresponds to MBOX[1], etc. | ||
| 21 | * | ||
| 22 | * At least three bytes are required, for the msg type and command, | ||
| 23 | * with additional bytes optional for additional data. | ||
| 24 | * | ||
| 25 | * Example: | ||
| 26 | * // Request EC info type 3 (EC firmware build date) | ||
| 27 | * $ echo 00 f0 38 00 03 00 > raw | ||
| 28 | * // View the result. The decoded ASCII result "12/21/18" is | ||
| 29 | * // included after the raw hex. | ||
| 30 | * $ cat raw | ||
| 31 | * 00 31 32 2f 32 31 2f 31 38 00 38 00 01 00 2f 00 .12/21/18.8... | ||
| 32 | */ | ||
| 33 | |||
| 34 | #include <linux/ctype.h> | ||
| 35 | #include <linux/debugfs.h> | ||
| 36 | #include <linux/fs.h> | ||
| 37 | #include <linux/module.h> | ||
| 38 | #include <linux/platform_data/wilco-ec.h> | ||
| 39 | #include <linux/platform_device.h> | ||
| 40 | |||
| 41 | #define DRV_NAME "wilco-ec-debugfs" | ||
| 42 | |||
| 43 | /* The 256 raw bytes will take up more space when represented as a hex string */ | ||
| 44 | #define FORMATTED_BUFFER_SIZE (EC_MAILBOX_DATA_SIZE_EXTENDED * 4) | ||
| 45 | |||
| 46 | struct wilco_ec_debugfs { | ||
| 47 | struct wilco_ec_device *ec; | ||
| 48 | struct dentry *dir; | ||
| 49 | size_t response_size; | ||
| 50 | u8 raw_data[EC_MAILBOX_DATA_SIZE_EXTENDED]; | ||
| 51 | u8 formatted_data[FORMATTED_BUFFER_SIZE]; | ||
| 52 | }; | ||
| 53 | static struct wilco_ec_debugfs *debug_info; | ||
| 54 | |||
| 55 | /** | ||
| 56 | * parse_hex_sentence() - Convert a ascii hex representation into byte array. | ||
| 57 | * @in: Input buffer of ascii. | ||
| 58 | * @isize: Length of input buffer. | ||
| 59 | * @out: Output buffer. | ||
| 60 | * @osize: Length of output buffer, e.g. max number of bytes to parse. | ||
| 61 | * | ||
| 62 | * An valid input is a series of ascii hexadecimal numbers, separated by spaces. | ||
| 63 | * An example valid input is | ||
| 64 | * " 00 f2 0 000076 6 0 ff" | ||
| 65 | * | ||
| 66 | * If an individual "word" within the hex sentence is longer than MAX_WORD_SIZE, | ||
| 67 | * then the sentence is illegal, and parsing will fail. | ||
| 68 | * | ||
| 69 | * Return: Number of bytes parsed, or negative error code on failure. | ||
| 70 | */ | ||
| 71 | static int parse_hex_sentence(const char *in, int isize, u8 *out, int osize) | ||
| 72 | { | ||
| 73 | int n_parsed = 0; | ||
| 74 | int word_start = 0; | ||
| 75 | int word_end; | ||
| 76 | int word_len; | ||
| 77 | /* Temp buffer for holding a "word" of chars that represents one byte */ | ||
| 78 | #define MAX_WORD_SIZE 16 | ||
| 79 | char tmp[MAX_WORD_SIZE + 1]; | ||
| 80 | u8 byte; | ||
| 81 | |||
| 82 | while (word_start < isize && n_parsed < osize) { | ||
| 83 | /* Find the start of the next word */ | ||
| 84 | while (word_start < isize && isspace(in[word_start])) | ||
| 85 | word_start++; | ||
| 86 | /* reached the end of the input before next word? */ | ||
| 87 | if (word_start >= isize) | ||
| 88 | break; | ||
| 89 | |||
| 90 | /* Find the end of this word */ | ||
| 91 | word_end = word_start; | ||
| 92 | while (word_end < isize && !isspace(in[word_end])) | ||
| 93 | word_end++; | ||
| 94 | |||
| 95 | /* Copy to a tmp NULL terminated string */ | ||
| 96 | word_len = word_end - word_start; | ||
| 97 | if (word_len > MAX_WORD_SIZE) | ||
| 98 | return -EINVAL; | ||
| 99 | memcpy(tmp, in + word_start, word_len); | ||
| 100 | tmp[word_len] = '\0'; | ||
| 101 | |||
| 102 | /* | ||
| 103 | * Convert from hex string, place in output. If fails to parse, | ||
| 104 | * just return -EINVAL because specific error code is only | ||
| 105 | * relevant for this one word, returning it would be confusing. | ||
| 106 | */ | ||
| 107 | if (kstrtou8(tmp, 16, &byte)) | ||
| 108 | return -EINVAL; | ||
| 109 | out[n_parsed++] = byte; | ||
| 110 | |||
| 111 | word_start = word_end; | ||
| 112 | } | ||
| 113 | return n_parsed; | ||
| 114 | } | ||
| 115 | |||
| 116 | /* The message type takes up two bytes*/ | ||
| 117 | #define TYPE_AND_DATA_SIZE ((EC_MAILBOX_DATA_SIZE) + 2) | ||
| 118 | |||
| 119 | static ssize_t raw_write(struct file *file, const char __user *user_buf, | ||
| 120 | size_t count, loff_t *ppos) | ||
| 121 | { | ||
| 122 | char *buf = debug_info->formatted_data; | ||
| 123 | struct wilco_ec_message msg; | ||
| 124 | u8 request_data[TYPE_AND_DATA_SIZE]; | ||
| 125 | ssize_t kcount; | ||
| 126 | int ret; | ||
| 127 | |||
| 128 | if (count > FORMATTED_BUFFER_SIZE) | ||
| 129 | return -EINVAL; | ||
| 130 | |||
| 131 | kcount = simple_write_to_buffer(buf, FORMATTED_BUFFER_SIZE, ppos, | ||
| 132 | user_buf, count); | ||
| 133 | if (kcount < 0) | ||
| 134 | return kcount; | ||
| 135 | |||
| 136 | ret = parse_hex_sentence(buf, kcount, request_data, TYPE_AND_DATA_SIZE); | ||
| 137 | if (ret < 0) | ||
| 138 | return ret; | ||
| 139 | /* Need at least two bytes for message type and one for command */ | ||
| 140 | if (ret < 3) | ||
| 141 | return -EINVAL; | ||
| 142 | |||
| 143 | /* Clear response data buffer */ | ||
| 144 | memset(debug_info->raw_data, '\0', EC_MAILBOX_DATA_SIZE_EXTENDED); | ||
| 145 | |||
| 146 | msg.type = request_data[0] << 8 | request_data[1]; | ||
| 147 | msg.flags = WILCO_EC_FLAG_RAW; | ||
| 148 | msg.command = request_data[2]; | ||
| 149 | msg.request_data = ret > 3 ? request_data + 3 : 0; | ||
| 150 | msg.request_size = ret - 3; | ||
| 151 | msg.response_data = debug_info->raw_data; | ||
| 152 | msg.response_size = EC_MAILBOX_DATA_SIZE; | ||
| 153 | |||
| 154 | /* Telemetry commands use extended response data */ | ||
| 155 | if (msg.type == WILCO_EC_MSG_TELEMETRY_LONG) { | ||
| 156 | msg.flags |= WILCO_EC_FLAG_EXTENDED_DATA; | ||
| 157 | msg.response_size = EC_MAILBOX_DATA_SIZE_EXTENDED; | ||
| 158 | } | ||
| 159 | |||
| 160 | ret = wilco_ec_mailbox(debug_info->ec, &msg); | ||
| 161 | if (ret < 0) | ||
| 162 | return ret; | ||
| 163 | debug_info->response_size = ret; | ||
| 164 | |||
| 165 | return count; | ||
| 166 | } | ||
| 167 | |||
| 168 | static ssize_t raw_read(struct file *file, char __user *user_buf, size_t count, | ||
| 169 | loff_t *ppos) | ||
| 170 | { | ||
| 171 | int fmt_len = 0; | ||
| 172 | |||
| 173 | if (debug_info->response_size) { | ||
| 174 | fmt_len = hex_dump_to_buffer(debug_info->raw_data, | ||
| 175 | debug_info->response_size, | ||
| 176 | 16, 1, debug_info->formatted_data, | ||
| 177 | FORMATTED_BUFFER_SIZE, true); | ||
| 178 | /* Only return response the first time it is read */ | ||
| 179 | debug_info->response_size = 0; | ||
| 180 | } | ||
| 181 | |||
| 182 | return simple_read_from_buffer(user_buf, count, ppos, | ||
| 183 | debug_info->formatted_data, fmt_len); | ||
| 184 | } | ||
| 185 | |||
| 186 | static const struct file_operations fops_raw = { | ||
| 187 | .owner = THIS_MODULE, | ||
| 188 | .read = raw_read, | ||
| 189 | .write = raw_write, | ||
| 190 | .llseek = no_llseek, | ||
| 191 | }; | ||
| 192 | |||
| 193 | /** | ||
| 194 | * wilco_ec_debugfs_probe() - Create the debugfs node | ||
| 195 | * @pdev: The platform device, probably created in core.c | ||
| 196 | * | ||
| 197 | * Try to create a debugfs node. If it fails, then we don't want to change | ||
| 198 | * behavior at all, this is for debugging after all. Just fail silently. | ||
| 199 | * | ||
| 200 | * Return: 0 always. | ||
| 201 | */ | ||
| 202 | static int wilco_ec_debugfs_probe(struct platform_device *pdev) | ||
| 203 | { | ||
| 204 | struct wilco_ec_device *ec = dev_get_drvdata(pdev->dev.parent); | ||
| 205 | |||
| 206 | debug_info = devm_kzalloc(&pdev->dev, sizeof(*debug_info), GFP_KERNEL); | ||
| 207 | if (!debug_info) | ||
| 208 | return 0; | ||
| 209 | debug_info->ec = ec; | ||
| 210 | debug_info->dir = debugfs_create_dir("wilco_ec", NULL); | ||
| 211 | if (!debug_info->dir) | ||
| 212 | return 0; | ||
| 213 | debugfs_create_file("raw", 0644, debug_info->dir, NULL, &fops_raw); | ||
| 214 | |||
| 215 | return 0; | ||
| 216 | } | ||
| 217 | |||
| 218 | static int wilco_ec_debugfs_remove(struct platform_device *pdev) | ||
| 219 | { | ||
| 220 | debugfs_remove_recursive(debug_info->dir); | ||
| 221 | |||
| 222 | return 0; | ||
| 223 | } | ||
| 224 | |||
| 225 | static struct platform_driver wilco_ec_debugfs_driver = { | ||
| 226 | .driver = { | ||
| 227 | .name = DRV_NAME, | ||
| 228 | }, | ||
| 229 | .probe = wilco_ec_debugfs_probe, | ||
| 230 | .remove = wilco_ec_debugfs_remove, | ||
| 231 | }; | ||
| 232 | |||
| 233 | module_platform_driver(wilco_ec_debugfs_driver); | ||
| 234 | |||
| 235 | MODULE_ALIAS("platform:" DRV_NAME); | ||
| 236 | MODULE_AUTHOR("Nick Crews <ncrews@chromium.org>"); | ||
| 237 | MODULE_LICENSE("GPL v2"); | ||
| 238 | 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 index 000000000000..f6ff29a11f1a --- /dev/null +++ b/drivers/platform/chrome/wilco_ec/mailbox.c | |||
| @@ -0,0 +1,237 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * Mailbox interface for Wilco Embedded Controller | ||
| 4 | * | ||
| 5 | * Copyright 2018 Google LLC | ||
| 6 | * | ||
| 7 | * The Wilco EC is similar to a typical ChromeOS embedded controller. | ||
| 8 | * It uses the same MEC based low-level communication and a similar | ||
| 9 | * protocol, but with some important differences. The EC firmware does | ||
| 10 | * not support the same mailbox commands so it is not registered as a | ||
| 11 | * cros_ec device type. | ||
| 12 | * | ||
| 13 | * Most messages follow a standard format, but there are some exceptions | ||
| 14 | * and an interface is provided to do direct/raw transactions that do not | ||
| 15 | * make assumptions about byte placement. | ||
| 16 | */ | ||
| 17 | |||
| 18 | #include <linux/delay.h> | ||
| 19 | #include <linux/device.h> | ||
| 20 | #include <linux/io.h> | ||
| 21 | #include <linux/platform_data/wilco-ec.h> | ||
| 22 | #include <linux/platform_device.h> | ||
| 23 | |||
| 24 | #include "../cros_ec_lpc_mec.h" | ||
| 25 | |||
| 26 | /* Version of mailbox interface */ | ||
| 27 | #define EC_MAILBOX_VERSION 0 | ||
| 28 | |||
| 29 | /* Command to start mailbox transaction */ | ||
| 30 | #define EC_MAILBOX_START_COMMAND 0xda | ||
| 31 | |||
| 32 | /* Version of EC protocol */ | ||
| 33 | #define EC_MAILBOX_PROTO_VERSION 3 | ||
| 34 | |||
| 35 | /* Number of header bytes to be counted as data bytes */ | ||
| 36 | #define EC_MAILBOX_DATA_EXTRA 2 | ||
| 37 | |||
| 38 | /* Maximum timeout */ | ||
| 39 | #define EC_MAILBOX_TIMEOUT HZ | ||
| 40 | |||
| 41 | /* EC response flags */ | ||
| 42 | #define EC_CMDR_DATA BIT(0) /* Data ready for host to read */ | ||
| 43 | #define EC_CMDR_PENDING BIT(1) /* Write pending to EC */ | ||
| 44 | #define EC_CMDR_BUSY BIT(2) /* EC is busy processing a command */ | ||
| 45 | #define EC_CMDR_CMD BIT(3) /* Last host write was a command */ | ||
| 46 | |||
| 47 | /** | ||
| 48 | * wilco_ec_response_timed_out() - Wait for EC response. | ||
| 49 | * @ec: EC device. | ||
| 50 | * | ||
| 51 | * Return: true if EC timed out, false if EC did not time out. | ||
| 52 | */ | ||
| 53 | static bool wilco_ec_response_timed_out(struct wilco_ec_device *ec) | ||
| 54 | { | ||
| 55 | unsigned long timeout = jiffies + EC_MAILBOX_TIMEOUT; | ||
| 56 | |||
| 57 | do { | ||
| 58 | if (!(inb(ec->io_command->start) & | ||
| 59 | (EC_CMDR_PENDING | EC_CMDR_BUSY))) | ||
| 60 | return false; | ||
| 61 | usleep_range(100, 200); | ||
| 62 | } while (time_before(jiffies, timeout)); | ||
| 63 | |||
| 64 | return true; | ||
| 65 | } | ||
| 66 | |||
| 67 | /** | ||
| 68 | * wilco_ec_checksum() - Compute 8-bit checksum over data range. | ||
| 69 | * @data: Data to checksum. | ||
| 70 | * @size: Number of bytes to checksum. | ||
| 71 | * | ||
| 72 | * Return: 8-bit checksum of provided data. | ||
| 73 | */ | ||
| 74 | static u8 wilco_ec_checksum(const void *data, size_t size) | ||
| 75 | { | ||
| 76 | u8 *data_bytes = (u8 *)data; | ||
| 77 | u8 checksum = 0; | ||
| 78 | size_t i; | ||
| 79 | |||
| 80 | for (i = 0; i < size; i++) | ||
| 81 | checksum += data_bytes[i]; | ||
| 82 | |||
| 83 | return checksum; | ||
| 84 | } | ||
| 85 | |||
| 86 | /** | ||
| 87 | * wilco_ec_prepare() - Prepare the request structure for the EC. | ||
| 88 | * @msg: EC message with request information. | ||
| 89 | * @rq: EC request structure to fill. | ||
| 90 | */ | ||
| 91 | static void wilco_ec_prepare(struct wilco_ec_message *msg, | ||
| 92 | struct wilco_ec_request *rq) | ||
| 93 | { | ||
| 94 | memset(rq, 0, sizeof(*rq)); | ||
| 95 | |||
| 96 | /* Handle messages without trimming bytes from the request */ | ||
| 97 | if (msg->request_size && msg->flags & WILCO_EC_FLAG_RAW_REQUEST) { | ||
| 98 | rq->reserved_raw = *(u8 *)msg->request_data; | ||
| 99 | msg->request_size--; | ||
| 100 | memmove(msg->request_data, msg->request_data + 1, | ||
| 101 | msg->request_size); | ||
| 102 | } | ||
| 103 | |||
| 104 | /* Fill in request packet */ | ||
| 105 | rq->struct_version = EC_MAILBOX_PROTO_VERSION; | ||
| 106 | rq->mailbox_id = msg->type; | ||
| 107 | rq->mailbox_version = EC_MAILBOX_VERSION; | ||
| 108 | rq->data_size = msg->request_size + EC_MAILBOX_DATA_EXTRA; | ||
| 109 | rq->command = msg->command; | ||
| 110 | |||
| 111 | /* Checksum header and data */ | ||
| 112 | rq->checksum = wilco_ec_checksum(rq, sizeof(*rq)); | ||
| 113 | rq->checksum += wilco_ec_checksum(msg->request_data, msg->request_size); | ||
| 114 | rq->checksum = -rq->checksum; | ||
| 115 | } | ||
| 116 | |||
| 117 | /** | ||
| 118 | * wilco_ec_transfer() - Perform actual data transfer. | ||
| 119 | * @ec: EC device. | ||
| 120 | * @msg: EC message data for request and response. | ||
| 121 | * @rq: Filled in request structure | ||
| 122 | * | ||
| 123 | * Context: ec->mailbox_lock should be held while using this function. | ||
| 124 | * Return: number of bytes received or negative error code on failure. | ||
| 125 | */ | ||
| 126 | static int wilco_ec_transfer(struct wilco_ec_device *ec, | ||
| 127 | struct wilco_ec_message *msg, | ||
| 128 | struct wilco_ec_request *rq) | ||
| 129 | { | ||
| 130 | struct wilco_ec_response *rs; | ||
| 131 | u8 checksum; | ||
| 132 | u8 flag; | ||
| 133 | size_t size; | ||
| 134 | |||
| 135 | /* Write request header, then data */ | ||
| 136 | cros_ec_lpc_io_bytes_mec(MEC_IO_WRITE, 0, sizeof(*rq), (u8 *)rq); | ||
| 137 | cros_ec_lpc_io_bytes_mec(MEC_IO_WRITE, sizeof(*rq), msg->request_size, | ||
| 138 | msg->request_data); | ||
| 139 | |||
| 140 | /* Start the command */ | ||
| 141 | outb(EC_MAILBOX_START_COMMAND, ec->io_command->start); | ||
| 142 | |||
| 143 | /* For some commands (eg shutdown) the EC will not respond, that's OK */ | ||
| 144 | if (msg->flags & WILCO_EC_FLAG_NO_RESPONSE) { | ||
| 145 | dev_dbg(ec->dev, "EC does not respond to this command\n"); | ||
| 146 | return 0; | ||
| 147 | } | ||
| 148 | |||
| 149 | /* Wait for it to complete */ | ||
| 150 | if (wilco_ec_response_timed_out(ec)) { | ||
| 151 | dev_dbg(ec->dev, "response timed out\n"); | ||
| 152 | return -ETIMEDOUT; | ||
| 153 | } | ||
| 154 | |||
| 155 | /* Check result */ | ||
| 156 | flag = inb(ec->io_data->start); | ||
| 157 | if (flag) { | ||
| 158 | dev_dbg(ec->dev, "bad response: 0x%02x\n", flag); | ||
| 159 | return -EIO; | ||
| 160 | } | ||
| 161 | |||
| 162 | if (msg->flags & WILCO_EC_FLAG_EXTENDED_DATA) | ||
| 163 | size = EC_MAILBOX_DATA_SIZE_EXTENDED; | ||
| 164 | else | ||
| 165 | size = EC_MAILBOX_DATA_SIZE; | ||
| 166 | |||
| 167 | /* Read back response */ | ||
| 168 | rs = ec->data_buffer; | ||
| 169 | checksum = cros_ec_lpc_io_bytes_mec(MEC_IO_READ, 0, | ||
| 170 | sizeof(*rs) + size, (u8 *)rs); | ||
| 171 | if (checksum) { | ||
| 172 | dev_dbg(ec->dev, "bad packet checksum 0x%02x\n", rs->checksum); | ||
| 173 | return -EBADMSG; | ||
| 174 | } | ||
| 175 | |||
| 176 | /* Check that the EC reported success */ | ||
| 177 | msg->result = rs->result; | ||
| 178 | if (msg->result) { | ||
| 179 | dev_dbg(ec->dev, "bad response: 0x%02x\n", msg->result); | ||
| 180 | return -EBADMSG; | ||
| 181 | } | ||
| 182 | |||
| 183 | /* Check the returned data size, skipping the header */ | ||
| 184 | if (rs->data_size != size) { | ||
| 185 | dev_dbg(ec->dev, "unexpected packet size (%u != %zu)", | ||
| 186 | rs->data_size, size); | ||
| 187 | return -EMSGSIZE; | ||
| 188 | } | ||
| 189 | |||
| 190 | /* Skip 1 response data byte unless specified */ | ||
| 191 | size = (msg->flags & WILCO_EC_FLAG_RAW_RESPONSE) ? 0 : 1; | ||
| 192 | if ((ssize_t) rs->data_size - size < msg->response_size) { | ||
| 193 | dev_dbg(ec->dev, "response data too short (%zd < %zu)", | ||
| 194 | (ssize_t) rs->data_size - size, msg->response_size); | ||
| 195 | return -EMSGSIZE; | ||
| 196 | } | ||
| 197 | |||
| 198 | /* Ignore response data bytes as requested */ | ||
| 199 | memcpy(msg->response_data, rs->data + size, msg->response_size); | ||
| 200 | |||
| 201 | /* Return actual amount of data received */ | ||
| 202 | return msg->response_size; | ||
| 203 | } | ||
| 204 | |||
| 205 | /** | ||
| 206 | * wilco_ec_mailbox() - Send EC request and receive EC response. | ||
| 207 | * @ec: EC device. | ||
| 208 | * @msg: EC message data for request and response. | ||
| 209 | * | ||
| 210 | * On entry msg->type, msg->flags, msg->command, msg->request_size, | ||
| 211 | * msg->response_size, and msg->request_data should all be filled in. | ||
| 212 | * | ||
| 213 | * On exit msg->result and msg->response_data will be filled. | ||
| 214 | * | ||
| 215 | * Return: number of bytes received or negative error code on failure. | ||
| 216 | */ | ||
| 217 | int wilco_ec_mailbox(struct wilco_ec_device *ec, struct wilco_ec_message *msg) | ||
| 218 | { | ||
| 219 | struct wilco_ec_request *rq; | ||
| 220 | int ret; | ||
| 221 | |||
| 222 | dev_dbg(ec->dev, "cmd=%02x type=%04x flags=%02x rslen=%zu rqlen=%zu\n", | ||
| 223 | msg->command, msg->type, msg->flags, msg->response_size, | ||
| 224 | msg->request_size); | ||
| 225 | |||
| 226 | /* Prepare request packet */ | ||
| 227 | rq = ec->data_buffer; | ||
| 228 | wilco_ec_prepare(msg, rq); | ||
| 229 | |||
| 230 | mutex_lock(&ec->mailbox_lock); | ||
| 231 | ret = wilco_ec_transfer(ec, msg, rq); | ||
| 232 | mutex_unlock(&ec->mailbox_lock); | ||
| 233 | |||
| 234 | return ret; | ||
| 235 | |||
| 236 | } | ||
| 237 | EXPORT_SYMBOL_GPL(wilco_ec_mailbox); | ||
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index e1a1f2b1cbba..a71734c41693 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig | |||
| @@ -1864,4 +1864,15 @@ config RTC_DRV_GOLDFISH | |||
| 1864 | Goldfish is a code name for the virtual platform developed by Google | 1864 | Goldfish is a code name for the virtual platform developed by Google |
| 1865 | for Android emulation. | 1865 | for Android emulation. |
| 1866 | 1866 | ||
| 1867 | config RTC_DRV_WILCO_EC | ||
| 1868 | tristate "Wilco EC RTC" | ||
| 1869 | depends on WILCO_EC | ||
| 1870 | default m | ||
| 1871 | help | ||
| 1872 | If you say yes here, you get read/write support for the Real Time | ||
| 1873 | Clock on the Wilco Embedded Controller (Wilco is a kind of Chromebook) | ||
| 1874 | |||
| 1875 | This can also be built as a module. If so, the module will | ||
| 1876 | be named "rtc_wilco_ec". | ||
| 1877 | |||
| 1867 | endif # RTC_CLASS | 1878 | endif # RTC_CLASS |
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 1bf9f75a7865..fe3962496685 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile | |||
| @@ -177,6 +177,7 @@ obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o | |||
| 177 | obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o | 177 | obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o |
| 178 | obj-$(CONFIG_RTC_DRV_VRTC) += rtc-mrst.o | 178 | obj-$(CONFIG_RTC_DRV_VRTC) += rtc-mrst.o |
| 179 | obj-$(CONFIG_RTC_DRV_VT8500) += rtc-vt8500.o | 179 | obj-$(CONFIG_RTC_DRV_VT8500) += rtc-vt8500.o |
| 180 | obj-$(CONFIG_RTC_DRV_WILCO_EC) += rtc-wilco-ec.o | ||
| 180 | obj-$(CONFIG_RTC_DRV_WM831X) += rtc-wm831x.o | 181 | obj-$(CONFIG_RTC_DRV_WM831X) += rtc-wm831x.o |
| 181 | obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o | 182 | obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o |
| 182 | obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o | 183 | 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 index 000000000000..e62bda0cb53e --- /dev/null +++ b/drivers/rtc/rtc-wilco-ec.c | |||
| @@ -0,0 +1,177 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * RTC interface for Wilco Embedded Controller with R/W abilities | ||
| 4 | * | ||
| 5 | * Copyright 2018 Google LLC | ||
| 6 | * | ||
| 7 | * The corresponding platform device is typically registered in | ||
| 8 | * drivers/platform/chrome/wilco_ec/core.c | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <linux/bcd.h> | ||
| 12 | #include <linux/err.h> | ||
| 13 | #include <linux/kernel.h> | ||
| 14 | #include <linux/module.h> | ||
| 15 | #include <linux/platform_device.h> | ||
| 16 | #include <linux/platform_data/wilco-ec.h> | ||
| 17 | #include <linux/rtc.h> | ||
| 18 | #include <linux/timekeeping.h> | ||
| 19 | |||
| 20 | #define EC_COMMAND_CMOS 0x7c | ||
| 21 | #define EC_CMOS_TOD_WRITE 0x02 | ||
| 22 | #define EC_CMOS_TOD_READ 0x08 | ||
| 23 | |||
| 24 | /** | ||
| 25 | * struct ec_rtc_read - Format of RTC returned by EC. | ||
| 26 | * @second: Second value (0..59) | ||
| 27 | * @minute: Minute value (0..59) | ||
| 28 | * @hour: Hour value (0..23) | ||
| 29 | * @day: Day value (1..31) | ||
| 30 | * @month: Month value (1..12) | ||
| 31 | * @year: Year value (full year % 100) | ||
| 32 | * @century: Century value (full year / 100) | ||
| 33 | * | ||
| 34 | * All values are presented in binary (not BCD). | ||
| 35 | */ | ||
| 36 | struct ec_rtc_read { | ||
| 37 | u8 second; | ||
| 38 | u8 minute; | ||
| 39 | u8 hour; | ||
| 40 | u8 day; | ||
| 41 | u8 month; | ||
| 42 | u8 year; | ||
| 43 | u8 century; | ||
| 44 | } __packed; | ||
| 45 | |||
| 46 | /** | ||
| 47 | * struct ec_rtc_write - Format of RTC sent to the EC. | ||
| 48 | * @param: EC_CMOS_TOD_WRITE | ||
| 49 | * @century: Century value (full year / 100) | ||
| 50 | * @year: Year value (full year % 100) | ||
| 51 | * @month: Month value (1..12) | ||
| 52 | * @day: Day value (1..31) | ||
| 53 | * @hour: Hour value (0..23) | ||
| 54 | * @minute: Minute value (0..59) | ||
| 55 | * @second: Second value (0..59) | ||
| 56 | * @weekday: Day of the week (0=Saturday) | ||
| 57 | * | ||
| 58 | * All values are presented in BCD. | ||
| 59 | */ | ||
| 60 | struct ec_rtc_write { | ||
| 61 | u8 param; | ||
| 62 | u8 century; | ||
| 63 | u8 year; | ||
| 64 | u8 month; | ||
| 65 | u8 day; | ||
| 66 | u8 hour; | ||
| 67 | u8 minute; | ||
| 68 | u8 second; | ||
| 69 | u8 weekday; | ||
| 70 | } __packed; | ||
| 71 | |||
| 72 | static int wilco_ec_rtc_read(struct device *dev, struct rtc_time *tm) | ||
| 73 | { | ||
| 74 | struct wilco_ec_device *ec = dev_get_drvdata(dev->parent); | ||
| 75 | u8 param = EC_CMOS_TOD_READ; | ||
| 76 | struct ec_rtc_read rtc; | ||
| 77 | struct wilco_ec_message msg = { | ||
| 78 | .type = WILCO_EC_MSG_LEGACY, | ||
| 79 | .flags = WILCO_EC_FLAG_RAW_RESPONSE, | ||
| 80 | .command = EC_COMMAND_CMOS, | ||
| 81 | .request_data = ¶m, | ||
| 82 | .request_size = sizeof(param), | ||
| 83 | .response_data = &rtc, | ||
| 84 | .response_size = sizeof(rtc), | ||
| 85 | }; | ||
| 86 | int ret; | ||
| 87 | |||
| 88 | ret = wilco_ec_mailbox(ec, &msg); | ||
| 89 | if (ret < 0) | ||
| 90 | return ret; | ||
| 91 | |||
| 92 | tm->tm_sec = rtc.second; | ||
| 93 | tm->tm_min = rtc.minute; | ||
| 94 | tm->tm_hour = rtc.hour; | ||
| 95 | tm->tm_mday = rtc.day; | ||
| 96 | tm->tm_mon = rtc.month - 1; | ||
| 97 | tm->tm_year = rtc.year + (rtc.century * 100) - 1900; | ||
| 98 | tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year); | ||
| 99 | |||
| 100 | /* Don't compute day of week, we don't need it. */ | ||
| 101 | tm->tm_wday = -1; | ||
| 102 | |||
| 103 | return 0; | ||
| 104 | } | ||
| 105 | |||
| 106 | static int wilco_ec_rtc_write(struct device *dev, struct rtc_time *tm) | ||
| 107 | { | ||
| 108 | struct wilco_ec_device *ec = dev_get_drvdata(dev->parent); | ||
| 109 | struct ec_rtc_write rtc; | ||
| 110 | struct wilco_ec_message msg = { | ||
| 111 | .type = WILCO_EC_MSG_LEGACY, | ||
| 112 | .flags = WILCO_EC_FLAG_RAW_RESPONSE, | ||
| 113 | .command = EC_COMMAND_CMOS, | ||
| 114 | .request_data = &rtc, | ||
| 115 | .request_size = sizeof(rtc), | ||
| 116 | }; | ||
| 117 | int year = tm->tm_year + 1900; | ||
| 118 | /* | ||
| 119 | * Convert from 0=Sunday to 0=Saturday for the EC | ||
| 120 | * We DO need to set weekday because the EC controls battery charging | ||
| 121 | * schedules that depend on the day of the week. | ||
| 122 | */ | ||
| 123 | int wday = tm->tm_wday == 6 ? 0 : tm->tm_wday + 1; | ||
| 124 | int ret; | ||
| 125 | |||
| 126 | rtc.param = EC_CMOS_TOD_WRITE; | ||
| 127 | rtc.century = bin2bcd(year / 100); | ||
| 128 | rtc.year = bin2bcd(year % 100); | ||
| 129 | rtc.month = bin2bcd(tm->tm_mon + 1); | ||
| 130 | rtc.day = bin2bcd(tm->tm_mday); | ||
| 131 | rtc.hour = bin2bcd(tm->tm_hour); | ||
| 132 | rtc.minute = bin2bcd(tm->tm_min); | ||
| 133 | rtc.second = bin2bcd(tm->tm_sec); | ||
| 134 | rtc.weekday = bin2bcd(wday); | ||
| 135 | |||
| 136 | ret = wilco_ec_mailbox(ec, &msg); | ||
| 137 | if (ret < 0) | ||
| 138 | return ret; | ||
| 139 | |||
| 140 | return 0; | ||
| 141 | } | ||
| 142 | |||
| 143 | static const struct rtc_class_ops wilco_ec_rtc_ops = { | ||
| 144 | .read_time = wilco_ec_rtc_read, | ||
| 145 | .set_time = wilco_ec_rtc_write, | ||
| 146 | }; | ||
| 147 | |||
| 148 | static int wilco_ec_rtc_probe(struct platform_device *pdev) | ||
| 149 | { | ||
| 150 | struct rtc_device *rtc; | ||
| 151 | |||
| 152 | rtc = devm_rtc_allocate_device(&pdev->dev); | ||
| 153 | if (IS_ERR(rtc)) | ||
| 154 | return PTR_ERR(rtc); | ||
| 155 | |||
| 156 | rtc->ops = &wilco_ec_rtc_ops; | ||
| 157 | /* EC only supports this century */ | ||
| 158 | rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; | ||
| 159 | rtc->range_max = RTC_TIMESTAMP_END_2099; | ||
| 160 | rtc->owner = THIS_MODULE; | ||
| 161 | |||
| 162 | return rtc_register_device(rtc); | ||
| 163 | } | ||
| 164 | |||
| 165 | static struct platform_driver wilco_ec_rtc_driver = { | ||
| 166 | .driver = { | ||
| 167 | .name = "rtc-wilco-ec", | ||
| 168 | }, | ||
| 169 | .probe = wilco_ec_rtc_probe, | ||
| 170 | }; | ||
| 171 | |||
| 172 | module_platform_driver(wilco_ec_rtc_driver); | ||
| 173 | |||
| 174 | MODULE_ALIAS("platform:rtc-wilco-ec"); | ||
| 175 | MODULE_AUTHOR("Nick Crews <ncrews@chromium.org>"); | ||
| 176 | MODULE_LICENSE("GPL v2"); | ||
| 177 | MODULE_DESCRIPTION("Wilco EC RTC driver"); | ||
