aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2023-02-21 17:23:39 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2023-02-21 17:23:39 -0800
commit5f5ce6bcfcc3abbaf690fca30a22d0dcf6f36d32 (patch)
tree1597ad6d459e09646e8d5c2022a36958ee7fc580
parent239451e90355be68130410ef8fadef8cd130a35d (diff)
parentb0d8a67715dae445c065c83a40a581d6563a341f (diff)
Merge tag 'tag-chrome-platform-for-v6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/chrome-platform/linux
Pull chrome platform updates from Tzung-Bi Shih: "New drivers: - cros_ec_uart for ChromeOS EC protocol over UART - cros_typec_vdm for USB PD Vendor Defined Message Improvements: - Preserve logs as much as possible when EC panics - Shutdown to refrain from potential HW damages when EC panics Fixes: - Fix DP_PORT_VDO to include DP_CAP_RECEPTACLE - Fix a lockdep false positive Cleanups: - Use sysfs_emit*() instead of scnprintf() - Use asm instead of asm-generic for unaligned.h Misc: - Rename module name from cros_ec_typec to cros-ec-typec - Minor fixes" * tag 'tag-chrome-platform-for-v6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/chrome-platform/linux: (34 commits) platform/chrome: cros_ec_typec: Fix spelling mistake platform/chrome: cros_typec_vdm: Add Attention support platform/chrome: cros_ec: Add VDM attention headers platform/chrome: cros_typec_vdm: Fix VDO copy platform/chrome: cros_ec_typec: allow deferred probe of switch handles platform/chrome: cros_ec_proto: remove big stub objects from stack platform/chrome: cros_ec_uart: fix negative type promoted to high platform/chrome: cros_ec: Use per-device lockdep key platform/chrome: fix kernel-doc warnings for cros_ec_command platform/chrome: fix kernel-doc warning for last_resume_result platform/chrome: fix kernel-doc warning for suspend_timeout_ms platform/chrome: fix kernel-doc warnings for panic notifier platform/chrome: cros_ec_lpc: initialize the buf variable platform/chrome: cros_ec: Fix panic notifier registration platform/chrome: cros_typec_switch: Check for retimer flag platform/chrome: cros_typec_switch: Use fwnode* prop check platform/chrome: cros_typec_vdm: Add VDM send support platform/chrome: cros_typec_vdm: Add VDM reply support platform/chrome: cros_ec_typec: Add initial VDM support platform/chrome: cros_ec_typec: Alter module name with hyphens ...
-rw-r--r--MAINTAINERS10
-rw-r--r--drivers/mfd/cros_ec_dev.c5
-rw-r--r--drivers/platform/chrome/Kconfig12
-rw-r--r--drivers/platform/chrome/Makefile4
-rw-r--r--drivers/platform/chrome/cros_ec.c15
-rw-r--r--drivers/platform/chrome/cros_ec_debugfs.c25
-rw-r--r--drivers/platform/chrome/cros_ec_lightbar.c14
-rw-r--r--drivers/platform/chrome/cros_ec_lpc.c12
-rw-r--r--drivers/platform/chrome/cros_ec_proto_test.c13
-rw-r--r--drivers/platform/chrome/cros_ec_sysfs.c40
-rw-r--r--drivers/platform/chrome/cros_ec_typec.c123
-rw-r--r--drivers/platform/chrome/cros_ec_typec.h85
-rw-r--r--drivers/platform/chrome/cros_ec_uart.c362
-rw-r--r--drivers/platform/chrome/cros_typec_switch.c16
-rw-r--r--drivers/platform/chrome/cros_typec_vdm.c148
-rw-r--r--drivers/platform/chrome/cros_typec_vdm.h13
-rw-r--r--drivers/platform/chrome/wilco_ec/sysfs.c3
-rw-r--r--include/linux/platform_data/cros_ec_commands.h69
-rw-r--r--include/linux/platform_data/cros_ec_proto.h24
19 files changed, 846 insertions, 147 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 27f3a8619afc..49609a55577d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4823,6 +4823,13 @@ S: Maintained
F: Documentation/devicetree/bindings/sound/google,cros-ec-codec.yaml
F: sound/soc/codecs/cros_ec_codec.*
+CHROMEOS EC UART DRIVER
+M: Bhanu Prakash Maiya <bhanumaiya@chromium.org>
+R: Benson Leung <bleung@chromium.org>
+R: Tzung-Bi Shih <tzungbi@kernel.org>
+S: Maintained
+F: drivers/platform/chrome/cros_ec_uart.c
+
CHROMEOS EC SUBDRIVERS
M: Benson Leung <bleung@chromium.org>
R: Guenter Roeck <groeck@chromium.org>
@@ -4836,8 +4843,9 @@ CHROMEOS EC USB TYPE-C DRIVER
M: Prashant Malani <pmalani@chromium.org>
L: chrome-platform@lists.linux.dev
S: Maintained
-F: drivers/platform/chrome/cros_ec_typec.c
+F: drivers/platform/chrome/cros_ec_typec.*
F: drivers/platform/chrome/cros_typec_switch.c
+F: drivers/platform/chrome/cros_typec_vdm.*
CHROMEOS EC USB PD NOTIFY DRIVER
M: Prashant Malani <pmalani@chromium.org>
diff --git a/drivers/mfd/cros_ec_dev.c b/drivers/mfd/cros_ec_dev.c
index 344ad03bdc42..02d4271dfe06 100644
--- a/drivers/mfd/cros_ec_dev.c
+++ b/drivers/mfd/cros_ec_dev.c
@@ -65,11 +65,6 @@ static const struct cros_feature_to_name cros_mcu_devices[] = {
.desc = "System Control Processor",
},
{
- .id = EC_FEATURE_SCP_C1,
- .name = CROS_EC_DEV_SCP_C1_NAME,
- .desc = "System Control Processor 2nd Core",
- },
- {
.id = EC_FEATURE_TOUCHPAD,
.name = CROS_EC_DEV_TP_NAME,
.desc = "Touchpad",
diff --git a/drivers/platform/chrome/Kconfig b/drivers/platform/chrome/Kconfig
index c1ca247987d2..7d82a0946e1c 100644
--- a/drivers/platform/chrome/Kconfig
+++ b/drivers/platform/chrome/Kconfig
@@ -119,6 +119,16 @@ config CROS_EC_SPI
response time cannot be guaranteed, we support ignoring
'pre-amble' bytes before the response actually starts.
+config CROS_EC_UART
+ tristate "ChromeOS Embedded Controller (UART)"
+ depends on CROS_EC && ACPI && SERIAL_DEV_BUS
+ help
+ If you say Y here, you get support for talking to the ChromeOS EC
+ through a UART, using a byte-level protocol.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cros_ec_uart.
+
config CROS_EC_LPC
tristate "ChromeOS Embedded Controller (LPC)"
depends on CROS_EC && ACPI && (X86 || COMPILE_TEST)
@@ -226,7 +236,7 @@ config CROS_EC_TYPEC
information from the Chrome OS EC.
To compile this driver as a module, choose M here: the module will be
- called cros_ec_typec.
+ called cros-ec-typec.
config CROS_HPS_I2C
tristate "ChromeOS HPS device"
diff --git a/drivers/platform/chrome/Makefile b/drivers/platform/chrome/Makefile
index f6068d077a40..9e26e45c4a37 100644
--- a/drivers/platform/chrome/Makefile
+++ b/drivers/platform/chrome/Makefile
@@ -15,8 +15,10 @@ obj-$(CONFIG_CROS_EC_ISHTP) += cros_ec_ishtp.o
obj-$(CONFIG_CROS_TYPEC_SWITCH) += cros_typec_switch.o
obj-$(CONFIG_CROS_EC_RPMSG) += cros_ec_rpmsg.o
obj-$(CONFIG_CROS_EC_SPI) += cros_ec_spi.o
+obj-$(CONFIG_CROS_EC_UART) += cros_ec_uart.o
cros_ec_lpcs-objs := cros_ec_lpc.o cros_ec_lpc_mec.o
-obj-$(CONFIG_CROS_EC_TYPEC) += cros_ec_typec.o
+cros-ec-typec-objs := cros_ec_typec.o cros_typec_vdm.o
+obj-$(CONFIG_CROS_EC_TYPEC) += cros-ec-typec.o
obj-$(CONFIG_CROS_EC_LPC) += cros_ec_lpcs.o
obj-$(CONFIG_CROS_EC_PROTO) += cros_ec_proto.o cros_ec_trace.o
obj-$(CONFIG_CROS_KBD_LED_BACKLIGHT) += cros_kbd_led_backlight.o
diff --git a/drivers/platform/chrome/cros_ec.c b/drivers/platform/chrome/cros_ec.c
index ec733f683f34..b895c8130bba 100644
--- a/drivers/platform/chrome/cros_ec.c
+++ b/drivers/platform/chrome/cros_ec.c
@@ -182,6 +182,7 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
int err = 0;
BLOCKING_INIT_NOTIFIER_HEAD(&ec_dev->event_notifier);
+ BLOCKING_INIT_NOTIFIER_HEAD(&ec_dev->panic_notifier);
ec_dev->max_request = sizeof(struct ec_params_hello);
ec_dev->max_response = sizeof(struct ec_response_get_protocol_info);
@@ -198,12 +199,14 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
if (!ec_dev->dout)
return -ENOMEM;
+ lockdep_register_key(&ec_dev->lockdep_key);
mutex_init(&ec_dev->lock);
+ lockdep_set_class(&ec_dev->lock, &ec_dev->lockdep_key);
err = cros_ec_query_all(ec_dev);
if (err) {
dev_err(dev, "Cannot identify the EC: error %d\n", err);
- return err;
+ goto destroy_mutex;
}
if (ec_dev->irq > 0) {
@@ -215,7 +218,7 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
if (err) {
dev_err(dev, "Failed to request IRQ %d: %d\n",
ec_dev->irq, err);
- return err;
+ goto destroy_mutex;
}
}
@@ -226,7 +229,8 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
if (IS_ERR(ec_dev->ec)) {
dev_err(ec_dev->dev,
"Failed to create CrOS EC platform device\n");
- return PTR_ERR(ec_dev->ec);
+ err = PTR_ERR(ec_dev->ec);
+ goto destroy_mutex;
}
if (ec_dev->max_passthru) {
@@ -292,6 +296,9 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
exit:
platform_device_unregister(ec_dev->ec);
platform_device_unregister(ec_dev->pd);
+destroy_mutex:
+ mutex_destroy(&ec_dev->lock);
+ lockdep_unregister_key(&ec_dev->lockdep_key);
return err;
}
EXPORT_SYMBOL(cros_ec_register);
@@ -309,6 +316,8 @@ void cros_ec_unregister(struct cros_ec_device *ec_dev)
if (ec_dev->pd)
platform_device_unregister(ec_dev->pd);
platform_device_unregister(ec_dev->ec);
+ mutex_destroy(&ec_dev->lock);
+ lockdep_unregister_key(&ec_dev->lockdep_key);
}
EXPORT_SYMBOL(cros_ec_unregister);
diff --git a/drivers/platform/chrome/cros_ec_debugfs.c b/drivers/platform/chrome/cros_ec_debugfs.c
index 21d973fc6be2..a98c529d8c69 100644
--- a/drivers/platform/chrome/cros_ec_debugfs.c
+++ b/drivers/platform/chrome/cros_ec_debugfs.c
@@ -38,6 +38,8 @@ static DECLARE_WAIT_QUEUE_HEAD(cros_ec_debugfs_log_wq);
* @log_mutex: mutex to protect circular buffer
* @log_poll_work: recurring task to poll EC for new console log data
* @panicinfo_blob: panicinfo debugfs blob
+ * @notifier_panic: notifier_block to let kernel to flush buffered log
+ * when EC panic
*/
struct cros_ec_debugfs {
struct cros_ec_dev *ec;
@@ -49,6 +51,7 @@ struct cros_ec_debugfs {
struct delayed_work log_poll_work;
/* EC panicinfo */
struct debugfs_blob_wrapper panicinfo_blob;
+ struct notifier_block notifier_panic;
};
/*
@@ -437,6 +440,22 @@ free:
return ret;
}
+static int cros_ec_debugfs_panic_event(struct notifier_block *nb,
+ unsigned long queued_during_suspend, void *_notify)
+{
+ struct cros_ec_debugfs *debug_info =
+ container_of(nb, struct cros_ec_debugfs, notifier_panic);
+
+ if (debug_info->log_buffer.buf) {
+ /* Force log poll work to run immediately */
+ mod_delayed_work(debug_info->log_poll_work.wq, &debug_info->log_poll_work, 0);
+ /* Block until log poll work finishes */
+ flush_delayed_work(&debug_info->log_poll_work);
+ }
+
+ return NOTIFY_DONE;
+}
+
static int cros_ec_debugfs_probe(struct platform_device *pd)
{
struct cros_ec_dev *ec = dev_get_drvdata(pd->dev.parent);
@@ -473,6 +492,12 @@ static int cros_ec_debugfs_probe(struct platform_device *pd)
debugfs_create_u16("suspend_timeout_ms", 0664, debug_info->dir,
&ec->ec_dev->suspend_timeout_ms);
+ debug_info->notifier_panic.notifier_call = cros_ec_debugfs_panic_event;
+ ret = blocking_notifier_chain_register(&ec->ec_dev->panic_notifier,
+ &debug_info->notifier_panic);
+ if (ret)
+ goto remove_debugfs;
+
ec->debug_info = debug_info;
dev_set_drvdata(&pd->dev, ec);
diff --git a/drivers/platform/chrome/cros_ec_lightbar.c b/drivers/platform/chrome/cros_ec_lightbar.c
index 1674105decfb..376425bbd8ff 100644
--- a/drivers/platform/chrome/cros_ec_lightbar.c
+++ b/drivers/platform/chrome/cros_ec_lightbar.c
@@ -34,7 +34,7 @@ static ssize_t interval_msec_show(struct device *dev,
{
unsigned long msec = lb_interval_jiffies * 1000 / HZ;
- return scnprintf(buf, PAGE_SIZE, "%lu\n", msec);
+ return sysfs_emit(buf, "%lu\n", msec);
}
static ssize_t interval_msec_store(struct device *dev,
@@ -169,7 +169,7 @@ static ssize_t version_show(struct device *dev,
if (!get_lightbar_version(ec, &version, &flags))
return -EIO;
- return scnprintf(buf, PAGE_SIZE, "%d %d\n", version, flags);
+ return sysfs_emit(buf, "%d %d\n", version, flags);
}
static ssize_t brightness_store(struct device *dev,
@@ -302,17 +302,15 @@ static ssize_t sequence_show(struct device *dev,
ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
if (ret < 0) {
- ret = scnprintf(buf, PAGE_SIZE, "XFER / EC ERROR %d / %d\n",
- ret, msg->result);
+ ret = sysfs_emit(buf, "XFER / EC ERROR %d / %d\n", ret, msg->result);
goto exit;
}
resp = (struct ec_response_lightbar *)msg->data;
if (resp->get_seq.num >= ARRAY_SIZE(seqname))
- ret = scnprintf(buf, PAGE_SIZE, "%d\n", resp->get_seq.num);
+ ret = sysfs_emit(buf, "%d\n", resp->get_seq.num);
else
- ret = scnprintf(buf, PAGE_SIZE, "%s\n",
- seqname[resp->get_seq.num]);
+ ret = sysfs_emit(buf, "%s\n", seqname[resp->get_seq.num]);
exit:
kfree(msg);
@@ -483,7 +481,7 @@ static ssize_t userspace_control_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- return scnprintf(buf, PAGE_SIZE, "%d\n", userspace_control);
+ return sysfs_emit(buf, "%d\n", userspace_control);
}
static ssize_t userspace_control_store(struct device *dev,
diff --git a/drivers/platform/chrome/cros_ec_lpc.c b/drivers/platform/chrome/cros_ec_lpc.c
index 7fc8f82280ac..68bba0fcafab 100644
--- a/drivers/platform/chrome/cros_ec_lpc.c
+++ b/drivers/platform/chrome/cros_ec_lpc.c
@@ -21,6 +21,7 @@
#include <linux/platform_data/cros_ec_proto.h>
#include <linux/platform_device.h>
#include <linux/printk.h>
+#include <linux/reboot.h>
#include <linux/suspend.h>
#include "cros_ec.h"
@@ -320,6 +321,15 @@ static void cros_ec_lpc_acpi_notify(acpi_handle device, u32 value, void *data)
ec_dev->last_event_time = cros_ec_get_time_ns();
+ if (value == ACPI_NOTIFY_CROS_EC_PANIC) {
+ dev_emerg(ec_dev->dev, "CrOS EC Panic Reported. Shutdown is imminent!");
+ blocking_notifier_call_chain(&ec_dev->panic_notifier, 0, ec_dev);
+ /* Begin orderly shutdown. Force shutdown after 1 second. */
+ hw_protection_shutdown("CrOS EC Panic", 1000);
+ /* Do not query for other events after a panic is reported */
+ return;
+ }
+
if (ec_dev->mkbp_event_supported)
do {
ret = cros_ec_get_next_event(ec_dev, NULL,
@@ -340,7 +350,7 @@ static int cros_ec_lpc_probe(struct platform_device *pdev)
struct acpi_device *adev;
acpi_status status;
struct cros_ec_device *ec_dev;
- u8 buf[2];
+ u8 buf[2] = {};
int irq, ret;
/*
diff --git a/drivers/platform/chrome/cros_ec_proto_test.c b/drivers/platform/chrome/cros_ec_proto_test.c
index c6a83df91ae1..5b9748e0463b 100644
--- a/drivers/platform/chrome/cros_ec_proto_test.c
+++ b/drivers/platform/chrome/cros_ec_proto_test.c
@@ -5,7 +5,8 @@
#include <kunit/test.h>
-#include <asm-generic/unaligned.h>
+#include <asm/unaligned.h>
+
#include <linux/platform_data/cros_ec_commands.h>
#include <linux/platform_data/cros_ec_proto.h>
@@ -2370,7 +2371,7 @@ static void cros_ec_proto_test_get_host_event_normal(struct kunit *test)
static void cros_ec_proto_test_check_features_cached(struct kunit *test)
{
int ret, i;
- struct cros_ec_dev ec;
+ static struct cros_ec_dev ec;
ec.features.flags[0] = EC_FEATURE_MASK_0(EC_FEATURE_FINGERPRINT);
ec.features.flags[1] = EC_FEATURE_MASK_0(EC_FEATURE_SCP);
@@ -2395,7 +2396,7 @@ static void cros_ec_proto_test_check_features_not_cached(struct kunit *test)
struct cros_ec_device *ec_dev = &priv->ec_dev;
struct ec_xfer_mock *mock;
int ret, i;
- struct cros_ec_dev ec;
+ static struct cros_ec_dev ec;
ec_dev->max_request = 0xff;
ec_dev->max_response = 0xee;
@@ -2448,7 +2449,7 @@ static void cros_ec_proto_test_get_sensor_count_normal(struct kunit *test)
struct cros_ec_device *ec_dev = &priv->ec_dev;
struct ec_xfer_mock *mock;
int ret;
- struct cros_ec_dev ec;
+ static struct cros_ec_dev ec;
ec_dev->max_request = 0xff;
ec_dev->max_response = 0xee;
@@ -2493,7 +2494,7 @@ static void cros_ec_proto_test_get_sensor_count_xfer_error(struct kunit *test)
struct cros_ec_device *ec_dev = &priv->ec_dev;
struct ec_xfer_mock *mock;
int ret;
- struct cros_ec_dev ec;
+ static struct cros_ec_dev ec;
ec_dev->max_request = 0xff;
ec_dev->max_response = 0xee;
@@ -2533,7 +2534,7 @@ static void cros_ec_proto_test_get_sensor_count_legacy(struct kunit *test)
struct cros_ec_device *ec_dev = &priv->ec_dev;
struct ec_xfer_mock *mock;
int ret, i;
- struct cros_ec_dev ec;
+ static struct cros_ec_dev ec;
struct {
u8 readmem_data;
int expected_result;
diff --git a/drivers/platform/chrome/cros_ec_sysfs.c b/drivers/platform/chrome/cros_ec_sysfs.c
index f07eabcf9494..09e3bf5e8ec6 100644
--- a/drivers/platform/chrome/cros_ec_sysfs.c
+++ b/drivers/platform/chrome/cros_ec_sysfs.c
@@ -27,10 +27,9 @@ static ssize_t reboot_show(struct device *dev,
{
int count = 0;
- count += scnprintf(buf + count, PAGE_SIZE - count,
- "ro|rw|cancel|cold|disable-jump|hibernate|cold-ap-off");
- count += scnprintf(buf + count, PAGE_SIZE - count,
- " [at-shutdown]\n");
+ count += sysfs_emit_at(buf, count,
+ "ro|rw|cancel|cold|disable-jump|hibernate|cold-ap-off");
+ count += sysfs_emit_at(buf, count, " [at-shutdown]\n");
return count;
}
@@ -138,12 +137,9 @@ static ssize_t version_show(struct device *dev,
/* Strings should be null-terminated, but let's be sure. */
r_ver->version_string_ro[sizeof(r_ver->version_string_ro) - 1] = '\0';
r_ver->version_string_rw[sizeof(r_ver->version_string_rw) - 1] = '\0';
- count += scnprintf(buf + count, PAGE_SIZE - count,
- "RO version: %s\n", r_ver->version_string_ro);
- count += scnprintf(buf + count, PAGE_SIZE - count,
- "RW version: %s\n", r_ver->version_string_rw);
- count += scnprintf(buf + count, PAGE_SIZE - count,
- "Firmware copy: %s\n",
+ count += sysfs_emit_at(buf, count, "RO version: %s\n", r_ver->version_string_ro);
+ count += sysfs_emit_at(buf, count, "RW version: %s\n", r_ver->version_string_rw);
+ count += sysfs_emit_at(buf, count, "Firmware copy: %s\n",
(r_ver->current_image < ARRAY_SIZE(image_names) ?
image_names[r_ver->current_image] : "?"));
@@ -152,13 +148,12 @@ static ssize_t version_show(struct device *dev,
msg->insize = EC_HOST_PARAM_SIZE;
ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
if (ret < 0) {
- count += scnprintf(buf + count, PAGE_SIZE - count,
+ count += sysfs_emit_at(buf, count,
"Build info: XFER / EC ERROR %d / %d\n",
ret, msg->result);
} else {
msg->data[EC_HOST_PARAM_SIZE - 1] = '\0';
- count += scnprintf(buf + count, PAGE_SIZE - count,
- "Build info: %s\n", msg->data);
+ count += sysfs_emit_at(buf, count, "Build info: %s\n", msg->data);
}
/* Get chip info. */
@@ -166,7 +161,7 @@ static ssize_t version_show(struct device *dev,
msg->insize = sizeof(*r_chip);
ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
if (ret < 0) {
- count += scnprintf(buf + count, PAGE_SIZE - count,
+ count += sysfs_emit_at(buf, count,
"Chip info: XFER / EC ERROR %d / %d\n",
ret, msg->result);
} else {
@@ -175,12 +170,9 @@ static ssize_t version_show(struct device *dev,
r_chip->vendor[sizeof(r_chip->vendor) - 1] = '\0';
r_chip->name[sizeof(r_chip->name) - 1] = '\0';
r_chip->revision[sizeof(r_chip->revision) - 1] = '\0';
- count += scnprintf(buf + count, PAGE_SIZE - count,
- "Chip vendor: %s\n", r_chip->vendor);
- count += scnprintf(buf + count, PAGE_SIZE - count,
- "Chip name: %s\n", r_chip->name);
- count += scnprintf(buf + count, PAGE_SIZE - count,
- "Chip revision: %s\n", r_chip->revision);
+ count += sysfs_emit_at(buf, count, "Chip vendor: %s\n", r_chip->vendor);
+ count += sysfs_emit_at(buf, count, "Chip name: %s\n", r_chip->name);
+ count += sysfs_emit_at(buf, count, "Chip revision: %s\n", r_chip->revision);
}
/* Get board version */
@@ -188,13 +180,13 @@ static ssize_t version_show(struct device *dev,
msg->insize = sizeof(*r_board);
ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
if (ret < 0) {
- count += scnprintf(buf + count, PAGE_SIZE - count,
+ count += sysfs_emit_at(buf, count,
"Board version: XFER / EC ERROR %d / %d\n",
ret, msg->result);
} else {
r_board = (struct ec_response_board_version *)msg->data;
- count += scnprintf(buf + count, PAGE_SIZE - count,
+ count += sysfs_emit_at(buf, count,
"Board version: %d\n",
r_board->board_version);
}
@@ -227,7 +219,7 @@ static ssize_t flashinfo_show(struct device *dev,
resp = (struct ec_response_flash_info *)msg->data;
- ret = scnprintf(buf, PAGE_SIZE,
+ ret = sysfs_emit(buf,
"FlashSize %d\nWriteSize %d\n"
"EraseSize %d\nProtectSize %d\n",
resp->flash_size, resp->write_block_size,
@@ -264,7 +256,7 @@ static ssize_t kb_wake_angle_show(struct device *dev,
goto exit;
resp = (struct ec_response_motion_sense *)msg->data;
- ret = scnprintf(buf, PAGE_SIZE, "%d\n", resp->kb_wake_angle.ret);
+ ret = sysfs_emit(buf, "%d\n", resp->kb_wake_angle.ret);
exit:
kfree(msg);
return ret;
diff --git a/drivers/platform/chrome/cros_ec_typec.c b/drivers/platform/chrome/cros_ec_typec.c
index 001b0de95a46..a673c3342470 100644
--- a/drivers/platform/chrome/cros_ec_typec.c
+++ b/drivers/platform/chrome/cros_ec_typec.c
@@ -7,92 +7,22 @@
*/
#include <linux/acpi.h>
-#include <linux/list.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_data/cros_ec_commands.h>
-#include <linux/platform_data/cros_ec_proto.h>
#include <linux/platform_data/cros_usbpd_notify.h>
#include <linux/platform_device.h>
-#include <linux/usb/pd.h>
#include <linux/usb/pd_vdo.h>
-#include <linux/usb/typec.h>
-#include <linux/usb/typec_altmode.h>
#include <linux/usb/typec_dp.h>
-#include <linux/usb/typec_mux.h>
-#include <linux/usb/typec_retimer.h>
#include <linux/usb/typec_tbt.h>
-#include <linux/usb/role.h>
+
+#include "cros_ec_typec.h"
+#include "cros_typec_vdm.h"
#define DRV_NAME "cros-ec-typec"
#define DP_PORT_VDO (DP_CONF_SET_PIN_ASSIGN(BIT(DP_PIN_ASSIGN_C) | BIT(DP_PIN_ASSIGN_D)) | \
- DP_CAP_DFP_D)
-
-/* Supported alt modes. */
-enum {
- CROS_EC_ALTMODE_DP = 0,
- CROS_EC_ALTMODE_TBT,
- CROS_EC_ALTMODE_MAX,
-};
-
-/* Container for altmode pointer nodes. */
-struct cros_typec_altmode_node {
- struct typec_altmode *amode;
- struct list_head list;
-};
-
-/* Per port data. */
-struct cros_typec_port {
- struct typec_port *port;
- /* Initial capabilities for the port. */
- struct typec_capability caps;
- struct typec_partner *partner;
- struct typec_cable *cable;
- /* SOP' plug. */
- struct typec_plug *plug;
- /* Port partner PD identity info. */
- struct usb_pd_identity p_identity;
- /* Port cable PD identity info. */
- struct usb_pd_identity c_identity;
- struct typec_switch *ori_sw;
- struct typec_mux *mux;
- struct typec_retimer *retimer;
- struct usb_role_switch *role_sw;
-
- /* Variables keeping track of switch state. */
- struct typec_mux_state state;
- uint8_t mux_flags;
- uint8_t role;
-
- struct typec_altmode *port_altmode[CROS_EC_ALTMODE_MAX];
-
- /* Flag indicating that PD partner discovery data parsing is completed. */
- bool sop_disc_done;
- bool sop_prime_disc_done;
- struct ec_response_typec_discovery *disc_data;
- struct list_head partner_mode_list;
- struct list_head plug_mode_list;
-
- /* PDO-related structs */
- struct usb_power_delivery *partner_pd;
- struct usb_power_delivery_capabilities *partner_src_caps;
- struct usb_power_delivery_capabilities *partner_sink_caps;
-};
-
-/* Platform-specific data for the Chrome OS EC Type C controller. */
-struct cros_typec_data {
- struct device *dev;
- struct cros_ec_device *ec;
- int num_ports;
- unsigned int pd_ctrl_ver;
- /* Array of ports, indexed by port number. */
- struct cros_typec_port *ports[EC_USB_PD_MAX_PORTS];
- struct notifier_block nb;
- struct work_struct port_work;
- bool typec_cmd_supported;
- bool needs_mux_ack;
-};
+ DP_CAP_DFP_D | DP_CAP_RECEPTACLE)
static int cros_typec_parse_port_props(struct typec_capability *cap,
struct fwnode_handle *fwnode,
@@ -145,27 +75,33 @@ static int cros_typec_get_switch_handles(struct cros_typec_port *port,
struct fwnode_handle *fwnode,
struct device *dev)
{
+ int ret = 0;
+
port->mux = fwnode_typec_mux_get(fwnode, NULL);
if (IS_ERR(port->mux)) {
- dev_dbg(dev, "Mux handle not found.\n");
+ ret = PTR_ERR(port->mux);
+ dev_dbg(dev, "Mux handle not found: %d.\n", ret);
goto mux_err;
}
port->retimer = fwnode_typec_retimer_get(fwnode);
if (IS_ERR(port->retimer)) {
- dev_dbg(dev, "Retimer handle not found.\n");
+ ret = PTR_ERR(port->retimer);
+ dev_dbg(dev, "Retimer handle not found: %d.\n", ret);
goto retimer_sw_err;
}
port->ori_sw = fwnode_typec_switch_get(fwnode);
if (IS_ERR(port->ori_sw)) {
- dev_dbg(dev, "Orientation switch handle not found.\n");
+ ret = PTR_ERR(port->ori_sw);
+ dev_dbg(dev, "Orientation switch handle not found: %d\n", ret);
goto ori_sw_err;
}
port->role_sw = fwnode_usb_role_switch_get(fwnode);
if (IS_ERR(port->role_sw)) {
- dev_dbg(dev, "USB role switch handle not found.\n");
+ ret = PTR_ERR(port->role_sw);
+ dev_dbg(dev, "USB role switch handle not found: %d\n", ret);
goto role_sw_err;
}
@@ -181,7 +117,7 @@ retimer_sw_err:
typec_mux_put(port->mux);
port->mux = NULL;
mux_err:
- return -ENODEV;
+ return ret;
}
static int cros_typec_add_partner(struct cros_typec_data *typec, int port_num,
@@ -342,6 +278,8 @@ static int cros_typec_register_port_altmodes(struct cros_typec_data *typec,
if (IS_ERR(amode))
return PTR_ERR(amode);
port->port_altmode[CROS_EC_ALTMODE_DP] = amode;
+ typec_altmode_set_drvdata(amode, port);
+ amode->ops = &port_amode_ops;
/*
* Register TBT compatibility alt mode. The EC will not enter the mode
@@ -355,6 +293,8 @@ static int cros_typec_register_port_altmodes(struct cros_typec_data *typec,
if (IS_ERR(amode))
return PTR_ERR(amode);
port->port_altmode[CROS_EC_ALTMODE_TBT] = amode;
+ typec_altmode_set_drvdata(amode, port);
+ amode->ops = &port_amode_ops;
port->state.alt = NULL;
port->state.mode = TYPEC_STATE_USB;
@@ -408,6 +348,8 @@ static int cros_typec_init_ports(struct cros_typec_data *typec)
goto unregister_ports;
}
+ cros_port->port_num = port_num;
+ cros_port->typec_data = typec;
typec->ports[port_num] = cros_port;
cap = &cros_port->caps;
@@ -423,9 +365,11 @@ static int cros_typec_init_ports(struct cros_typec_data *typec)
}
ret = cros_typec_get_switch_handles(cros_port, fwnode, dev);
- if (ret)
- dev_dbg(dev, "No switch control for port %d\n",
- port_num);
+ if (ret) {
+ dev_dbg(dev, "No switch control for port %d, err: %d\n", port_num, ret);
+ if (ret == -EPROBE_DEFER)
+ goto unregister_ports;
+ }
ret = cros_typec_register_port_altmodes(typec, port_num);
if (ret) {
@@ -1064,6 +1008,21 @@ static void cros_typec_handle_status(struct cros_typec_data *typec, int port_num
"Failed SOP Disc event clear, port: %d\n", port_num);
}
}
+
+ if (resp.events & PD_STATUS_EVENT_VDM_REQ_REPLY) {
+ cros_typec_handle_vdm_response(typec, port_num);
+ ret = cros_typec_send_clear_event(typec, port_num, PD_STATUS_EVENT_VDM_REQ_REPLY);
+ if (ret < 0)
+ dev_warn(typec->dev, "Failed VDM Reply event clear, port: %d\n", port_num);
+ }
+
+ if (resp.events & PD_STATUS_EVENT_VDM_ATTENTION) {
+ cros_typec_handle_vdm_attention(typec, port_num);
+ ret = cros_typec_send_clear_event(typec, port_num, PD_STATUS_EVENT_VDM_ATTENTION);
+ if (ret < 0)
+ dev_warn(typec->dev, "Failed VDM attention event clear, port: %d\n",
+ port_num);
+ }
}
static int cros_typec_port_update(struct cros_typec_data *typec, int port_num)
diff --git a/drivers/platform/chrome/cros_ec_typec.h b/drivers/platform/chrome/cros_ec_typec.h
new file mode 100644
index 000000000000..deda180a646f
--- /dev/null
+++ b/drivers/platform/chrome/cros_ec_typec.h
@@ -0,0 +1,85 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __CROS_EC_TYPEC__
+#define __CROS_EC_TYPEC__
+
+#include <linux/list.h>
+#include <linux/notifier.h>
+#include <linux/platform_data/cros_ec_proto.h>
+#include <linux/usb/pd.h>
+#include <linux/usb/role.h>
+#include <linux/usb/typec.h>
+#include <linux/usb/typec_altmode.h>
+#include <linux/usb/typec_mux.h>
+#include <linux/usb/typec_retimer.h>
+#include <linux/workqueue.h>
+
+/* Supported alt modes. */
+enum {
+ CROS_EC_ALTMODE_DP = 0,
+ CROS_EC_ALTMODE_TBT,
+ CROS_EC_ALTMODE_MAX,
+};
+
+/* Container for altmode pointer nodes. */
+struct cros_typec_altmode_node {
+ struct typec_altmode *amode;
+ struct list_head list;
+};
+
+/* Platform-specific data for the Chrome OS EC Type C controller. */
+struct cros_typec_data {
+ struct device *dev;
+ struct cros_ec_device *ec;
+ int num_ports;
+ unsigned int pd_ctrl_ver;
+ /* Array of ports, indexed by port number. */
+ struct cros_typec_port *ports[EC_USB_PD_MAX_PORTS];
+ struct notifier_block nb;
+ struct work_struct port_work;
+ bool typec_cmd_supported;
+ bool needs_mux_ack;
+};
+
+/* Per port data. */
+struct cros_typec_port {
+ struct typec_port *port;
+ int port_num;
+ /* Initial capabilities for the port. */
+ struct typec_capability caps;
+ struct typec_partner *partner;
+ struct typec_cable *cable;
+ /* SOP' plug. */
+ struct typec_plug *plug;
+ /* Port partner PD identity info. */
+ struct usb_pd_identity p_identity;
+ /* Port cable PD identity info. */
+ struct usb_pd_identity c_identity;
+ struct typec_switch *ori_sw;
+ struct typec_mux *mux;
+ struct typec_retimer *retimer;
+ struct usb_role_switch *role_sw;
+
+ /* Variables keeping track of switch state. */
+ struct typec_mux_state state;
+ uint8_t mux_flags;
+ uint8_t role;
+
+ struct typec_altmode *port_altmode[CROS_EC_ALTMODE_MAX];
+
+ /* Flag indicating that PD partner discovery data parsing is completed. */
+ bool sop_disc_done;
+ bool sop_prime_disc_done;
+ struct ec_response_typec_discovery *disc_data;
+ struct list_head partner_mode_list;
+ struct list_head plug_mode_list;
+
+ /* PDO-related structs */
+ struct usb_power_delivery *partner_pd;
+ struct usb_power_delivery_capabilities *partner_src_caps;
+ struct usb_power_delivery_capabilities *partner_sink_caps;
+
+ struct cros_typec_data *typec_data;
+};
+
+#endif /* __CROS_EC_TYPEC__ */
diff --git a/drivers/platform/chrome/cros_ec_uart.c b/drivers/platform/chrome/cros_ec_uart.c
new file mode 100644
index 000000000000..788246559bbb
--- /dev/null
+++ b/drivers/platform/chrome/cros_ec_uart.c
@@ -0,0 +1,362 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * UART interface for ChromeOS Embedded Controller
+ *
+ * Copyright 2020-2022 Google LLC.
+ */
+
+#include <linux/acpi.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_data/cros_ec_proto.h>
+#include <linux/serdev.h>
+#include <linux/slab.h>
+#include <uapi/linux/sched/types.h>
+
+#include "cros_ec.h"
+
+/*
+ * EC sends contiguous bytes of response packet on UART AP RX.
+ * TTY driver in AP accumulates incoming bytes and calls the registered callback
+ * function. Byte count can range from 1 to MAX bytes supported by EC.
+ * This driver should wait for long time for all callbacks to be processed.
+ * Considering the worst case scenario, wait for 500 msec. This timeout should
+ * account for max latency and some additional guard time.