Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1543624 > unrolled thread

[PATCH 0/3] mfd: cros_ec: various improvements

Started byThierry Escande <thierry.escande@collabora.com>
First post2016-12-16 19:00 +0100
Last post2016-12-16 19:00 +0100
Articles 4 — 1 participant

Back to article view | Back to linux.kernel


Contents

  [PATCH 0/3] mfd: cros_ec: various improvements Thierry Escande <thierry.escande@collabora.com> - 2016-12-16 19:00 +0100
    [PATCH 1/3] mfd: cros_ec: Prevent data transfer while device is suspended Thierry Escande <thierry.escande@collabora.com> - 2016-12-16 19:00 +0100
    [PATCH 2/3] mfd: cros_ec: Send suspend state notification to EC Thierry Escande <thierry.escande@collabora.com> - 2016-12-16 19:00 +0100
    [PATCH 3/3] mfd: cros_ec: Add ACPI GPE handler for LID0 devices Thierry Escande <thierry.escande@collabora.com> - 2016-12-16 19:00 +0100

#1543624 — [PATCH 0/3] mfd: cros_ec: various improvements

FromThierry Escande <thierry.escande@collabora.com>
Date2016-12-16 19:00 +0100
Subject[PATCH 0/3] mfd: cros_ec: various improvements
Message-ID<sP4Xv-6N6-5@gated-at.bofh.it>
Hi,

This series adds some improvements to the ChromeOS EC driver.
- New EC host commands are sent through suspend/resume ops.
- A flag now protect data transfer while device is suspended.
- LID0 device GPE now stays enabled for lid to work in suspend to
  idle path.

This patchset depends on [1] to apply.
[1] https://lkml.org/lkml/2016/12/2/360

Regards,
 Thierry

Archana Patni (1):
  mfd: cros_ec: Add ACPI GPE handler for LID0 devices

Joseph Lo (1):
  mfd: cros_ec: Prevent data transfer while device is suspended

Shawn Nematbakhsh (1):
  mfd: cros_ec: Send suspend state notification to EC

 drivers/mfd/cros_ec.c                   | 144 ++++++++++++++++++++++++++++++++
 drivers/platform/chrome/cros_ec_proto.c |   5 ++
 include/linux/mfd/cros_ec.h             |   2 +
 include/linux/mfd/cros_ec_commands.h    |  14 ++++
 4 files changed, 165 insertions(+)

-- 
2.7.4

[toc] | [next] | [standalone]


#1543626 — [PATCH 1/3] mfd: cros_ec: Prevent data transfer while device is suspended

FromThierry Escande <thierry.escande@collabora.com>
Date2016-12-16 19:00 +0100
Subject[PATCH 1/3] mfd: cros_ec: Prevent data transfer while device is suspended
Message-ID<sP4Xw-6N6-15@gated-at.bofh.it>
In reply to#1543624
From: Joseph Lo <josephl@nvidia.com>

The cros_ec driver is still active while the device is suspended.
Besides that, it also tries to transfer data even after the I2C host had
been suspended. This patch uses a simple flag to prevent this.

Signed-off-by: Joseph Lo <josephl@nvidia.com>
Signed-off-by: Thierry Escande <thierry.escande@collabora.com>
---
 drivers/mfd/cros_ec.c                   | 2 ++
 drivers/platform/chrome/cros_ec_proto.c | 5 +++++
 include/linux/mfd/cros_ec.h             | 2 ++
 3 files changed, 9 insertions(+)

diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c
index abd8342..ad48633 100644
--- a/drivers/mfd/cros_ec.c
+++ b/drivers/mfd/cros_ec.c
@@ -165,6 +165,7 @@ int cros_ec_suspend(struct cros_ec_device *ec_dev)
 
 	disable_irq(ec_dev->irq);
 	ec_dev->was_wake_device = ec_dev->wake_enabled;
+	ec_dev->suspended = true;
 
 	return 0;
 }
@@ -179,6 +180,7 @@ static void cros_ec_drain_events(struct cros_ec_device *ec_dev)
 
 int cros_ec_resume(struct cros_ec_device *ec_dev)
 {
+	ec_dev->suspended = false;
 	enable_irq(ec_dev->irq);
 
 	/*
diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c
index 04053fe..ed5dee7 100644
--- a/drivers/platform/chrome/cros_ec_proto.c
+++ b/drivers/platform/chrome/cros_ec_proto.c
@@ -447,6 +447,11 @@ static int get_next_event(struct cros_ec_device *ec_dev)
 	struct cros_ec_command *msg = (struct cros_ec_command *)&buffer;
 	int ret;
 
+	if (ec_dev->suspended) {
+		dev_dbg(ec_dev->dev, "Device suspended.\n");
+		return -EHOSTDOWN;
+	}
+
 	msg->version = 0;
 	msg->command = EC_CMD_GET_NEXT_EVENT;
 	msg->insize = sizeof(ec_dev->event_data);
diff --git a/include/linux/mfd/cros_ec.h b/include/linux/mfd/cros_ec.h
index 76f7ef4..d585bf0 100644
--- a/include/linux/mfd/cros_ec.h
+++ b/include/linux/mfd/cros_ec.h
@@ -103,6 +103,7 @@ struct cros_ec_command {
  * @din_size: size of din buffer to allocate (zero to use static din)
  * @dout_size: size of dout buffer to allocate (zero to use static dout)
  * @wake_enabled: true if this device can wake the system from sleep
+ * @suspended: true if this device had been suspended
  * @cmd_xfer: send command to EC and get response
  *     Returns the number of bytes received if the communication succeeded, but
  *     that doesn't mean the EC was happy with the command. The caller
@@ -136,6 +137,7 @@ struct cros_ec_device {
 	int din_size;
 	int dout_size;
 	bool wake_enabled;
+	bool suspended;
 	int (*cmd_xfer)(struct cros_ec_device *ec,
 			struct cros_ec_command *msg);
 	int (*pkt_xfer)(struct cros_ec_device *ec,
-- 
2.7.4

[toc] | [prev] | [next] | [standalone]


#1543627 — [PATCH 2/3] mfd: cros_ec: Send suspend state notification to EC

FromThierry Escande <thierry.escande@collabora.com>
Date2016-12-16 19:00 +0100
Subject[PATCH 2/3] mfd: cros_ec: Send suspend state notification to EC
Message-ID<sP4Xv-6N6-7@gated-at.bofh.it>
In reply to#1543624
From: Shawn Nematbakhsh <shawnn@chromium.org>

Notify EC when going to or returning from suspend so that proper actions
related to wake events can be taken.

Signed-off-by: Shawn Nematbakhsh <shawnn@chromium.org>
Signed-off-by: Thierry Escande <thierry.escande@collabora.com>
---
 drivers/mfd/cros_ec.c                | 49 ++++++++++++++++++++++++++++++++++++
 include/linux/mfd/cros_ec_commands.h | 14 +++++++++++
 2 files changed, 63 insertions(+)

diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c
index ad48633..b8a5080 100644
--- a/drivers/mfd/cros_ec.c
+++ b/drivers/mfd/cros_ec.c
@@ -23,6 +23,7 @@
 #include <linux/module.h>
 #include <linux/mfd/core.h>
 #include <linux/mfd/cros_ec.h>
+#include <linux/suspend.h>
 #include <asm/unaligned.h>
 
 #define CROS_EC_DEV_EC_INDEX 0
@@ -65,6 +66,24 @@ static irqreturn_t ec_irq_thread(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
+static int cros_ec_sleep_event(struct cros_ec_device *ec_dev, u8 sleep_event)
+{
+	struct {
+		struct cros_ec_command msg;
+		struct ec_params_host_sleep_event req;
+	} __packed buf;
+
+	memset(&buf, 0, sizeof(buf));
+
+	buf.req.sleep_event = sleep_event;
+
+	buf.msg.command = EC_CMD_HOST_SLEEP_EVENT;
+	buf.msg.version = 0;
+	buf.msg.outsize = sizeof(buf.req);
+
+	return cros_ec_cmd_xfer(ec_dev, &buf.msg);
+}
+
 int cros_ec_register(struct cros_ec_device *ec_dev)
 {
 	struct device *dev = ec_dev->dev;
@@ -136,6 +155,15 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
 		}
 	}
 
+	/*
+	 * Clear sleep event - this will fail harmlessly on platforms that
+	 * don't implement the sleep event host command.
+	 */
+	err = cros_ec_sleep_event(ec_dev, 0);
+	if (err < 0)
+		dev_dbg(ec_dev->dev, "Error %d clearing sleep event to ec",
+			err);
+
 	dev_info(dev, "Chrome EC device registered\n");
 
 	return 0;
@@ -159,6 +187,16 @@ EXPORT_SYMBOL(cros_ec_remove);
 int cros_ec_suspend(struct cros_ec_device *ec_dev)
 {
 	struct device *dev = ec_dev->dev;
+	int ret;
+	u8 sleep_event;
+
+	sleep_event = pm_suspend_via_firmware() ? HOST_SLEEP_EVENT_S3_RESUME :
+						  HOST_SLEEP_EVENT_S0IX_RESUME;
+
+	ret = cros_ec_sleep_event(ec_dev, sleep_event);
+	if (ret < 0)
+		dev_dbg(ec_dev->dev, "Error %d sending suspend event to ec",
+			ret);
 
 	if (device_may_wakeup(dev))
 		ec_dev->wake_enabled = !enable_irq_wake(ec_dev->irq);
@@ -180,9 +218,20 @@ static void cros_ec_drain_events(struct cros_ec_device *ec_dev)
 
 int cros_ec_resume(struct cros_ec_device *ec_dev)
 {
+	int ret;
+	u8 sleep_event;
+
 	ec_dev->suspended = false;
 	enable_irq(ec_dev->irq);
 
+	sleep_event = pm_suspend_via_firmware() ? HOST_SLEEP_EVENT_S3_RESUME :
+						  HOST_SLEEP_EVENT_S0IX_RESUME;
+
+	ret = cros_ec_sleep_event(ec_dev, sleep_event);
+	if (ret < 0)
+		dev_dbg(ec_dev->dev, "Error %d sending resume event to ec",
+			ret);
+
 	/*
 	 * In some cases, we need to distinguish between events that occur
 	 * during suspend if the EC is not a wake source. For example,
diff --git a/include/linux/mfd/cros_ec_commands.h b/include/linux/mfd/cros_ec_commands.h
index 76728ff..4d55132 100644
--- a/include/linux/mfd/cros_ec_commands.h
+++ b/include/linux/mfd/cros_ec_commands.h
@@ -2304,6 +2304,20 @@ struct ec_params_ext_power_current_limit {
 	uint32_t limit; /* in mA */
 } __packed;
 
+/* Inform the EC when entering a sleep state */
+#define EC_CMD_HOST_SLEEP_EVENT 0xa9
+
+enum host_sleep_event {
+	HOST_SLEEP_EVENT_S3_SUSPEND   = 1,
+	HOST_SLEEP_EVENT_S3_RESUME    = 2,
+	HOST_SLEEP_EVENT_S0IX_SUSPEND = 3,
+	HOST_SLEEP_EVENT_S0IX_RESUME  = 4
+};
+
+struct ec_params_host_sleep_event {
+	uint8_t sleep_event;
+} __packed;
+
 /*****************************************************************************/
 /* Smart battery pass-through */
 
-- 
2.7.4

[toc] | [prev] | [next] | [standalone]


#1543629 — [PATCH 3/3] mfd: cros_ec: Add ACPI GPE handler for LID0 devices

FromThierry Escande <thierry.escande@collabora.com>
Date2016-12-16 19:00 +0100
Subject[PATCH 3/3] mfd: cros_ec: Add ACPI GPE handler for LID0 devices
Message-ID<sP4Xw-6N6-19@gated-at.bofh.it>
In reply to#1543624
From: Archana Patni <archana.patni@intel.com>

This patch installs an ACPI GPE handler for LID0 ACPI device to indicate
ACPI core that this GPE should stay enabled for lid to work in suspend
to idle path.

Signed-off-by: Archana Patni <archana.patni@intel.com>
Signed-off-by: Thierry Escande <thierry.escande@collabora.com>
---
 drivers/mfd/cros_ec.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 95 insertions(+), 2 deletions(-)

diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c
index b8a5080..628718e 100644
--- a/drivers/mfd/cros_ec.c
+++ b/drivers/mfd/cros_ec.c
@@ -17,6 +17,9 @@
  * battery charging and regulator control, firmware update.
  */
 
+#ifdef CONFIG_ACPI
+#include <linux/acpi.h>
+#endif
 #include <linux/of_platform.h>
 #include <linux/interrupt.h>
 #include <linux/slab.h>
@@ -29,6 +32,73 @@
 #define CROS_EC_DEV_EC_INDEX 0
 #define CROS_EC_DEV_PD_INDEX 1
 
+#ifdef CONFIG_ACPI
+
+#define ACPI_LID_DEVICE      "LID0"
+
+static int ec_wake_gpe = -EINVAL;
+
+/*
+ * This handler indicates to ACPI core that this GPE should stay enabled for
+ * lid to work in suspend to idle path.
+ */
+static u32 cros_ec_gpe_handler(acpi_handle gpe_device, u32 gpe_number,
+			       void *data)
+{
+	return ACPI_INTERRUPT_HANDLED | ACPI_REENABLE_GPE;
+}
+
+/*
+ * Get ACPI GPE for LID0 device.
+ */
+static int cros_ec_get_ec_wake_gpe(struct device *dev)
+{
+	struct acpi_device *cros_acpi_dev;
+	struct acpi_device *adev;
+	acpi_handle handle;
+	acpi_status status;
+	int ret;
+
+	cros_acpi_dev = ACPI_COMPANION(dev);
+
+	if (!cros_acpi_dev || !cros_acpi_dev->parent ||
+	   !cros_acpi_dev->parent->handle)
+		return -EINVAL;
+
+	status = acpi_get_handle(cros_acpi_dev->parent->handle, ACPI_LID_DEVICE,
+				 &handle);
+	if (ACPI_FAILURE(status))
+		return -EINVAL;
+
+	ret = acpi_bus_get_device(handle, &adev);
+	if (ret)
+		return ret;
+
+	return adev->wakeup.gpe_number;
+}
+
+static int cros_ec_install_handler(struct device *dev)
+{
+	acpi_status status;
+
+	ec_wake_gpe = cros_ec_get_ec_wake_gpe(dev);
+
+	if (ec_wake_gpe < 0)
+		return ec_wake_gpe;
+
+	status = acpi_install_gpe_handler(NULL, ec_wake_gpe,
+					  ACPI_GPE_EDGE_TRIGGERED,
+					  &cros_ec_gpe_handler, NULL);
+	if (ACPI_FAILURE(status))
+		return -ENODEV;
+
+	dev_info(dev, "Initialized, GPE = 0x%x\n", ec_wake_gpe);
+
+	return 0;
+}
+
+#endif
+
 static struct cros_ec_platform ec_p = {
 	.ec_name = CROS_EC_DEV_NAME,
 	.cmd_offset = EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_EC_INDEX),
@@ -166,6 +236,10 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
 
 	dev_info(dev, "Chrome EC device registered\n");
 
+#ifdef CONFIG_ACPI
+	cros_ec_install_handler(dev);
+#endif
+
 	return 0;
 
 fail_mfd:
@@ -179,6 +253,17 @@ int cros_ec_remove(struct cros_ec_device *ec_dev)
 {
 	mfd_remove_devices(ec_dev->dev);
 
+#ifdef CONFIG_ACPI
+	if (ec_wake_gpe >= 0) {
+		acpi_status status;
+
+		status = acpi_remove_gpe_handler(NULL, ec_wake_gpe,
+						 &cros_ec_gpe_handler);
+		if (ACPI_FAILURE(status))
+			pr_err("failed to remove gpe handler\n");
+	}
+#endif
+
 	return 0;
 }
 EXPORT_SYMBOL(cros_ec_remove);
@@ -190,8 +275,16 @@ int cros_ec_suspend(struct cros_ec_device *ec_dev)
 	int ret;
 	u8 sleep_event;
 
-	sleep_event = pm_suspend_via_firmware() ? HOST_SLEEP_EVENT_S3_RESUME :
-						  HOST_SLEEP_EVENT_S0IX_RESUME;
+	if (!pm_suspend_via_firmware()) {
+		sleep_event = HOST_SLEEP_EVENT_S0IX_SUSPEND;
+#ifdef CONFIG_ACPI
+		/* Clearing the GPE status for any pending event */
+		if (ec_wake_gpe >= 0)
+			acpi_clear_gpe(NULL, ec_wake_gpe);
+#endif
+	} else {
+		sleep_event = HOST_SLEEP_EVENT_S3_SUSPEND;
+	}
 
 	ret = cros_ec_sleep_event(ec_dev, sleep_event);
 	if (ret < 0)
-- 
2.7.4

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web