cros_ec: Add support for switches
On x86 platforms the EC provides a way to read 'switches', which are
on/off values determined by the EC.
Add a new driver method for this and implement it for LPC.
Signed-off-by: Simon Glass <sjg@chromium.org>
diff --git a/arch/sandbox/include/asm/test.h b/arch/sandbox/include/asm/test.h
index 8363ca73..1cb960a 100644
--- a/arch/sandbox/include/asm/test.h
+++ b/arch/sandbox/include/asm/test.h
@@ -61,6 +61,7 @@
*/
enum cros_ec_test_t {
CROSECT_BREAK_HELLO = BIT(1),
+ CROSECT_LID_OPEN = BIT(2),
};
/**
diff --git a/cmd/cros_ec.c b/cmd/cros_ec.c
index 77656a2..a222c75 100644
--- a/cmd/cros_ec.c
+++ b/cmd/cros_ec.c
@@ -162,6 +162,41 @@
return 0;
}
+static const char *const switch_name[8] = {
+ "lid open",
+ "power button pressed",
+ "write-protect disabled",
+ NULL,
+ "dedicated recovery",
+ NULL,
+ NULL,
+ NULL,
+};
+
+static int do_show_switches(struct udevice *dev)
+{
+ uint switches;
+ int ret;
+ uint i;
+
+ ret = cros_ec_get_switches(dev);
+ if (ret < 0)
+ return log_msg_ret("get", ret);
+ switches = ret;
+ for (i = 0; i < ARRAY_SIZE(switch_name); i++) {
+ uint mask = 1 << i;
+
+ if (switches & mask) {
+ if (switch_name[i])
+ printf("%s\n", switch_name[i]);
+ else
+ printf("unknown %02x\n", mask);
+ }
+ }
+
+ return 0;
+}
+
static int do_cros_ec(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{
@@ -213,6 +248,11 @@
if (ret)
printf("Error: %d\n", ret);
+ } else if (!strcmp("switches", cmd)) {
+ ret = do_show_switches(dev);
+
+ if (ret)
+ printf("Error: %d\n", ret);
} else if (0 == strcmp("curimage", cmd)) {
enum ec_current_image image;
@@ -453,6 +493,7 @@
"crosec id Read CROS-EC ID\n"
"crosec info Read CROS-EC info\n"
"crosec features Read CROS-EC features\n"
+ "crosec switches Read CROS-EC switches\n"
"crosec curimage Read CROS-EC current image\n"
"crosec hash Read CROS-EC hash\n"
"crosec reboot [rw | ro | cold] Reboot CROS-EC\n"
diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c
index fd2f2ab..0bc28e8 100644
--- a/drivers/misc/cros_ec.c
+++ b/drivers/misc/cros_ec.c
@@ -1557,6 +1557,22 @@
return 0;
}
+int cros_ec_get_switches(struct udevice *dev)
+{
+ struct dm_cros_ec_ops *ops;
+ int ret;
+
+ ops = dm_cros_ec_get_ops(dev);
+ if (!ops->get_switches)
+ return -ENOSYS;
+
+ ret = ops->get_switches(dev);
+ if (ret < 0)
+ return log_msg_ret("get", ret);
+
+ return ret;
+}
+
UCLASS_DRIVER(cros_ec) = {
.id = UCLASS_CROS_EC,
.name = "cros-ec",
diff --git a/drivers/misc/cros_ec_lpc.c b/drivers/misc/cros_ec_lpc.c
index e0002b9..f403759 100644
--- a/drivers/misc/cros_ec_lpc.c
+++ b/drivers/misc/cros_ec_lpc.c
@@ -207,6 +207,12 @@
return 0;
}
+/* Return the byte of EC switch states */
+static int cros_ec_lpc_get_switches(struct udevice *dev)
+{
+ return inb(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_SWITCHES);
+}
+
/*
* Test if LPC command args are supported.
*
@@ -239,6 +245,7 @@
.packet = cros_ec_lpc_packet,
.command = cros_ec_lpc_command,
.check_version = cros_ec_lpc_check_version,
+ .get_switches = cros_ec_lpc_get_switches,
};
static const struct udevice_id cros_ec_ids[] = {
diff --git a/drivers/misc/cros_ec_sandbox.c b/drivers/misc/cros_ec_sandbox.c
index 7213313..38a2614 100644
--- a/drivers/misc/cros_ec_sandbox.c
+++ b/drivers/misc/cros_ec_sandbox.c
@@ -75,6 +75,7 @@
* @keyscan: Current keyscan information (bit set for each row/column pressed)
* @recovery_req: Keyboard recovery requested
* @test_flags: Flags that control behaviour for tests
+ * @switches: Current switches value (EC_SWITCH_)
*/
struct ec_state {
u8 vbnv_context[EC_VBNV_BLOCK_SIZE_V2];
@@ -541,6 +542,14 @@
}
}
+/* Return the byte of EC switch states */
+static int cros_ec_sandbox_get_switches(struct udevice *dev)
+{
+ struct ec_state *ec = dev_get_priv(dev);
+
+ return ec->test_flags & CROSECT_LID_OPEN ? EC_SWITCH_LID_OPEN : 0;
+}
+
void sandbox_cros_ec_set_test_flags(struct udevice *dev, uint flags)
{
struct ec_state *ec = dev_get_priv(dev);
@@ -603,6 +612,7 @@
struct dm_cros_ec_ops cros_ec_ops = {
.packet = cros_ec_sandbox_packet,
+ .get_switches = cros_ec_sandbox_get_switches,
};
static const struct udevice_id cros_ec_ids[] = {
diff --git a/include/cros_ec.h b/include/cros_ec.h
index 26e3f3b..cb91343 100644
--- a/include/cros_ec.h
+++ b/include/cros_ec.h
@@ -279,6 +279,16 @@
* @return number of bytes in response, or -ve on error
*/
int (*packet)(struct udevice *dev, int out_bytes, int in_bytes);
+
+ /**
+ * get_switches() - Get value of EC switches
+ *
+ * This is currently supported on the LPC EC.
+ *
+ * @dev: Device to use
+ * @return current switches value, or -ENOSYS if not supported
+ */
+ int (*get_switches)(struct udevice *dev);
};
#define dm_cros_ec_get_ops(dev) \
@@ -577,4 +587,13 @@
*/
int cros_ec_check_feature(struct udevice *dev, uint feature);
+/**
+ * cros_ec_get_switches() - Get switches value
+ *
+ * @dev: CROS-EC device
+ * @return switches value, or -ENOSYS if not supported, or other -ve value on
+ * other error
+ */
+int cros_ec_get_switches(struct udevice *dev);
+
#endif
diff --git a/test/dm/cros_ec.c b/test/dm/cros_ec.c
index a1ec9fc..4377440 100644
--- a/test/dm/cros_ec.c
+++ b/test/dm/cros_ec.c
@@ -75,3 +75,29 @@
return 0;
}
DM_TEST(dm_test_cros_ec_features, UT_TESTF_SCAN_FDT);
+
+static int dm_test_cros_ec_switches(struct unit_test_state *uts)
+{
+ struct udevice *dev;
+
+ ut_assertok(uclass_first_device_err(UCLASS_CROS_EC, &dev));
+ ut_asserteq(0, cros_ec_get_switches(dev));
+
+ /* try the command */
+ console_record_reset();
+ ut_assertok(run_command("crosec switches", 0));
+ ut_assert_console_end();
+
+ /* Open the lid and check the switch changes */
+ sandbox_cros_ec_set_test_flags(dev, CROSECT_LID_OPEN);
+ ut_asserteq(EC_SWITCH_LID_OPEN, cros_ec_get_switches(dev));
+
+ /* try the command */
+ console_record_reset();
+ ut_assertok(run_command("crosec switches", 0));
+ ut_assert_nextline("lid open");
+ ut_assert_console_end();
+
+ return 0;
+}
+DM_TEST(dm_test_cros_ec_switches, UT_TESTF_SCAN_FDT);