All of lore.kernel.org
 help / color / mirror / Atom feed
From: Daniel Drake <dsd@laptop.org>
To: tglx@linutronix.de, mingo@redhat.com, hpa@zytor.com, x86@kernel.org
Cc: linux-kernel@vger.kernel.org, dilinger@queued.net,
	Daniel Drake <dsd@laptop.org>
Subject: [PATCH 07/11] x86, olpc-xo1-sci: Add GPE handler and ebook switch functionality
Date: Sat, 30 Apr 2011 13:32:26 +0100	[thread overview]
Message-ID: <1304166750-31125-8-git-send-email-dsd@laptop.org> (raw)
In-Reply-To: <1304166750-31125-1-git-send-email-dsd@laptop.org>

The EC in the OLPC XO-1 delivers GPE events to provide various
notifications. Add the basic code for GPE/EC event processing and
enable the ebook switch, which can be used as a wakeup source.

Signed-off-by: Daniel Drake <dsd@laptop.org>
---
 arch/x86/Kconfig                      |    2 +
 arch/x86/include/asm/olpc.h           |    5 +-
 arch/x86/platform/olpc/olpc-xo1-sci.c |  170 ++++++++++++++++++++++++++++++++-
 include/linux/cs5535.h                |    8 ++
 4 files changed, 182 insertions(+), 3 deletions(-)

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index c273c62..0e62cd5 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -2077,7 +2077,9 @@ config OLPC_XO1_SCI
 	depends on OLPC && OLPC_XO1_PM
 	---help---
 	  Add support for SCI-based features of the OLPC XO-1 laptop:
+	   - EC-driven system wakeups
 	   - Power button
+	   - Ebook switch
 
 endif # X86_32
 
diff --git a/arch/x86/include/asm/olpc.h b/arch/x86/include/asm/olpc.h
index 0e56d01..87bdbca 100644
--- a/arch/x86/include/asm/olpc.h
+++ b/arch/x86/include/asm/olpc.h
@@ -111,6 +111,7 @@ extern int olpc_ec_cmd(unsigned char cmd, unsigned char *inbuf, size_t inlen,
 #define EC_WRITE_SCI_MASK		0x1b
 #define EC_WAKE_UP_WLAN			0x24
 #define EC_WLAN_LEAVE_RESET		0x25
+#define EC_READ_EB_MODE			0x2a
 #define EC_SET_SCI_INHIBIT		0x32
 #define EC_SET_SCI_INHIBIT_RELEASE	0x34
 #define EC_WLAN_ENTER_RESET		0x35
@@ -144,7 +145,7 @@ extern int olpc_ec_cmd(unsigned char cmd, unsigned char *inbuf, size_t inlen,
 #define OLPC_GPIO_SMB_CLK      14
 #define OLPC_GPIO_SMB_DATA     15
 #define OLPC_GPIO_WORKAUX	geode_gpio(24)
-#define OLPC_GPIO_LID		geode_gpio(26)
-#define OLPC_GPIO_ECSCI		geode_gpio(27)
+#define OLPC_GPIO_LID		26
+#define OLPC_GPIO_ECSCI		27
 
 #endif /* _ASM_X86_OLPC_H */
diff --git a/arch/x86/platform/olpc/olpc-xo1-sci.c b/arch/x86/platform/olpc/olpc-xo1-sci.c
index 8fbf961..9de2a00 100644
--- a/arch/x86/platform/olpc/olpc-xo1-sci.c
+++ b/arch/x86/platform/olpc/olpc-xo1-sci.c
@@ -12,12 +12,15 @@
  */
 
 #include <linux/cs5535.h>
+#include <linux/device.h>
+#include <linux/gpio.h>
 #include <linux/input.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/pm.h>
 #include <linux/mfd/core.h>
 #include <linux/suspend.h>
+#include <linux/workqueue.h>
 
 #include <asm/io.h>
 #include <asm/msr.h>
@@ -28,8 +31,60 @@
 
 static unsigned long acpi_base;
 static struct input_dev *power_button_idev;
+static struct input_dev *ebook_switch_idev;
+
 static int sci_irq;
 
+/* Report current ebook switch state through input layer */
+static void send_ebook_state(void)
+{
+	unsigned char state;
+
+	if (olpc_ec_cmd(EC_READ_EB_MODE, NULL, 0, &state, 1)) {
+		pr_err(PFX "failed to get ebook state\n");
+		return;
+	}
+
+	input_report_switch(ebook_switch_idev, SW_TABLET_MODE, state);
+	input_sync(ebook_switch_idev);
+}
+
+/*
+ * Process all items in the EC's SCI queue.
+ *
+ * This is handled in a workqueue because olpc_ec_cmd can be slow (and
+ * can even timeout).
+ *
+ * If propagate_events is false, the queue is drained without events being
+ * generated for the interrupts.
+ */
+static void process_sci_queue(bool propagate_events)
+{
+	int r;
+	u16 data;
+
+	do {
+		r = olpc_ec_sci_query(&data);
+		if (r || !data)
+			break;
+
+		pr_debug(PFX "SCI 0x%x received\n", data);
+
+		if (data == EC_SCI_SRC_EBOOK && propagate_events)
+			send_ebook_state();
+	} while (data);
+
+	if (r)
+		pr_err(PFX "Failed to clear SCI queue");
+}
+
+static void process_sci_queue_work(struct work_struct *work)
+{
+	process_sci_queue(true);
+}
+
+static DECLARE_WORK(sci_work, process_sci_queue_work);
+
 static irqreturn_t xo1_sci_intr(int irq, void *dev_id)
 {
 	struct platform_device *pdev = dev_id;
@@ -51,6 +106,11 @@ static irqreturn_t xo1_sci_intr(int irq, void *dev_id)
 		input_sync(power_button_idev);
 	}
 
+	if (gpe & CS5536_GPIOM7_PME_FLAG) { /* EC GPIO */
+		cs5535_gpio_set(OLPC_GPIO_ECSCI, GPIO_NEGATIVE_EDGE_STS);
+		schedule_work(&sci_work);
+	}
+
 	return IRQ_HANDLED;
 }
 
@@ -60,6 +120,19 @@ static int xo1_sci_suspend(struct platform_device *pdev, pm_message_t state)
 		olpc_xo1_pm_wakeup_set(CS5536_PM_PWRBTN);
 	else
 		olpc_xo1_pm_wakeup_clear(CS5536_PM_PWRBTN);
+
+	if (device_may_wakeup(&ebook_switch_idev->dev))
+		olpc_ec_wakeup_set(EC_SCI_SRC_EBOOK);
+	else
+		olpc_ec_wakeup_clear(EC_SCI_SRC_EBOOK);
+
+	return 0;
+}
+
+static int xo1_sci_resume(struct platform_device *pdev)
+{
+	/* Enable all EC events */
+	olpc_ec_mask_write(EC_SCI_SRC_ALL);
 	return 0;
 }
 
@@ -104,6 +177,37 @@ static int __devinit setup_sci_interrupt(struct platform_device *pdev)
 	return r;
 }
 
+static int __devinit setup_ec_sci(void)
+{
+	int r;
+
+	r = gpio_request(OLPC_GPIO_ECSCI, "OLPC-ECSCI");
+	if (r)
+		return r;
+
+	gpio_direction_input(OLPC_GPIO_ECSCI);
+
+	/* Clear pending EC SCI events */
+	cs5535_gpio_set(OLPC_GPIO_ECSCI, GPIO_NEGATIVE_EDGE_STS);
+	cs5535_gpio_set(OLPC_GPIO_ECSCI, GPIO_POSITIVE_EDGE_STS);
+
+	/* Enable EC SCI events */
+	cs5535_gpio_set(OLPC_GPIO_ECSCI, GPIO_EVENTS_ENABLE);
+
+	/* Set the SCI to cause a PME event on group 7 */
+	cs5535_gpio_setup_event(OLPC_GPIO_ECSCI, 7, 1);
+
+	/* And have group 7 also fire the SCI interrupt */
+	cs5535_gpio_set_irq(7, sci_irq);
+
+	return 0;
+}
+
+static void free_ec_sci(void)
+{
+	gpio_free(OLPC_GPIO_ECSCI);
+}
+
 static int __devinit setup_power_button(struct platform_device *pdev)
 {
 	int r;
@@ -135,6 +239,37 @@ static void free_power_button(void)
 	input_free_device(power_button_idev);
 }
 
+static int __devinit setup_ebook_switch(struct platform_device *pdev)
+{
+	int r;
+
+	ebook_switch_idev = input_allocate_device();
+	if (!ebook_switch_idev)
+		return -ENOMEM;
+
+	ebook_switch_idev->name = "EBook Switch";
+	ebook_switch_idev->phys = DRV_NAME "/input1";
+	set_bit(EV_SW, ebook_switch_idev->evbit);
+	set_bit(SW_TABLET_MODE, ebook_switch_idev->swbit);
+
+	ebook_switch_idev->dev.parent = &pdev->dev;
+	device_set_wakeup_capable(&ebook_switch_idev->dev, true);
+
+	r = input_register_device(ebook_switch_idev);
+	if (r) {
+		dev_err(&pdev->dev, "failed to register ebook switch: %d\n", r);
+		input_free_device(ebook_switch_idev);
+	}
+
+	return r;
+}
+
+static void free_ebook_switch(void)
+{
+	input_unregister_device(ebook_switch_idev);
+	input_free_device(ebook_switch_idev);
+}
+
 static int __devinit xo1_sci_probe(struct platform_device *pdev)
 {
 	struct resource *res;
@@ -159,10 +294,39 @@ static int __devinit xo1_sci_probe(struct platform_device *pdev)
 	if (r)
 		return r;
 
+	r = setup_ebook_switch(pdev);
+	if (r)
+		goto err_ebook;
+
+	r = setup_ec_sci();
+	if (r)
+		goto err_ecsci;
+
+	/* Enable PME generation for EC-generated events */
+	outl(CS5536_GPIOM7_PME_EN, acpi_base + CS5536_PM_GPE0_EN);
+
+	/* Clear pending events */
+	outl(0xffffffff, acpi_base + CS5536_PM_GPE0_STS);
+	process_sci_queue(false);
+
+	/* Initial sync */
+	send_ebook_state();
+
 	r = setup_sci_interrupt(pdev);
 	if (r)
-		free_power_button();
+		goto err_sci;
 
+	/* Enable all EC events */
+	olpc_ec_mask_write(EC_SCI_SRC_ALL);
+
+	return r;
+
+err_sci:
+	free_ec_sci();
+err_ecsci:
+	free_ebook_switch();
+err_ebook:
+	free_power_button();
 	return r;
 }
 
@@ -170,6 +334,9 @@ static int __devexit xo1_sci_remove(struct platform_device *pdev)
 {
 	mfd_cell_disable(pdev);
 	free_irq(sci_irq, pdev);
+	cancel_work_sync(&sci_work);
+	free_ec_sci();
+	free_ebook_switch();
 	free_power_button();
 	acpi_base = 0;
 	return 0;
@@ -182,6 +349,7 @@ static struct platform_driver xo1_sci_driver = {
 	.probe = xo1_sci_probe,
 	.remove = __devexit_p(xo1_sci_remove),
 	.suspend = xo1_sci_suspend,
+	.resume = xo1_sci_resume,
 };
 
 static int __init xo1_sci_init(void)
diff --git a/include/linux/cs5535.h b/include/linux/cs5535.h
index 6f78235..95c16ac 100644
--- a/include/linux/cs5535.h
+++ b/include/linux/cs5535.h
@@ -73,6 +73,7 @@
 #define CS5536_PM1_EN		0x02
 #define CS5536_PM1_CNT		0x08
 #define CS5536_PM_GPE0_STS	0x18
+#define CS5536_PM_GPE0_EN	0x1c
 
 /* CS5536_PM1_STS bits */
 #define CS5536_WAK_FLAG		(1 << 15)
@@ -81,6 +82,13 @@
 /* CS5536_PM1_EN bits */
 #define CS5536_PM_PWRBTN	(1 << 8)
 
+/* CS5536_PM_GPE0_STS bits */
+#define CS5536_GPIOM7_PME_FLAG	(1 << 31)
+#define CS5536_GPIOM6_PME_FLAG	(1 << 30)
+
+/* CS5536_PM_GPE0_EN bits */
+#define CS5536_GPIOM7_PME_EN	(1 << 31)
+
 /* VSA2 magic values */
 #define VSA_VRC_INDEX		0xAC1C
 #define VSA_VRC_DATA		0xAC1E
-- 
1.7.4.4


  parent reply	other threads:[~2011-04-30 13:01 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-04-30 12:32 [PATCH 0/11] OLPC Power Management Daniel Drake
2011-04-30 12:32 ` [PATCH 01/11] x86, olpc: add missing elements to device tree Daniel Drake
2011-04-30 12:32   ` Daniel Drake
2011-04-30 12:32 ` [PATCH 02/11] x86, olpc: Move CS5536-related constants to cs5535.h Daniel Drake
2011-04-30 12:32 ` [PATCH 03/11] x86, olpc: rename olpc-xo1 to olpc-xo1-pm Daniel Drake
2011-04-30 12:32 ` [PATCH 04/11] x86, olpc: Add XO-1 suspend/resume support Daniel Drake
2011-04-30 12:32 ` [PATCH 05/11] x86, olpc: Add XO-1 SCI driver and power button control Daniel Drake
2011-04-30 12:32 ` [PATCH 06/11] x86, olpc: EC SCI wakeup mask functionality Daniel Drake
2011-04-30 12:32 ` Daniel Drake [this message]
2011-05-16  9:08   ` [PATCH 07/11] x86, olpc-xo1-sci: Add GPE handler and ebook switch functionality Sebastian Andrzej Siewior
2011-05-16 16:07     ` Andres Salomon
2011-05-24 21:40     ` Daniel Drake
2011-05-31 11:28       ` Sebastian Andrzej Siewior
2011-05-31 20:48         ` Daniel Drake
2011-06-09  0:25           ` Andres Salomon
2011-04-30 12:32 ` [PATCH 08/11] x86, olpc-xo1-sci: Add lid " Daniel Drake
2011-04-30 12:32 ` [PATCH 09/11] x86, olpc-xo1-sci: Propagate power supply/battery events Daniel Drake
2011-04-30 12:32 ` [PATCH 10/11] x86, olpc: Add XO-1 RTC driver Daniel Drake
2011-05-16  9:18   ` Sebastian Andrzej Siewior
2011-05-16  9:18     ` Sebastian Andrzej Siewior
2011-05-19 19:35   ` Grant Likely
2011-04-30 12:32 ` [PATCH 11/11] x86, olpc: Add XO-1.5 SCI driver Daniel Drake
2011-05-16  9:24   ` Sebastian Andrzej Siewior
2011-05-24 21:52     ` Daniel Drake
2011-05-24 21:52       ` Daniel Drake
2011-04-30 17:07 ` [PATCH 0/11] OLPC Power Management Andres Salomon
2011-05-14 19:09   ` Daniel Drake

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1304166750-31125-8-git-send-email-dsd@laptop.org \
    --to=dsd@laptop.org \
    --cc=dilinger@queued.net \
    --cc=hpa@zytor.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@redhat.com \
    --cc=tglx@linutronix.de \
    --cc=x86@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.