ODROID-C5: gpio/irqchip: Add GPIO wakeup feature on suspend/resume

Signed-off-by: Dongjin Kim <tobetter@gmail.com>
Change-Id: I5b1292f7af270fadaa75062e3b2ab12b1978495f
diff --git a/drivers/gpio/irqchip/irq-meson-gpio.c b/drivers/gpio/irqchip/irq-meson-gpio.c
index 77a86ea..d5574f3 100644
--- a/drivers/gpio/irqchip/irq-meson-gpio.c
+++ b/drivers/gpio/irqchip/irq-meson-gpio.c
@@ -17,6 +17,9 @@
 #ifdef CONFIG_AMLOGIC_MODIFY
 #include <linux/amlogic/glb_timer.h>
 #endif
+#if defined(CONFIG_ARCH_MESON_ODROID_COMMON)
+#include <linux/amlogic/aml_mbox.h>
+#endif
 
 #define NUM_CHANNEL 8
 #define MAX_INPUT_MUX 256
@@ -26,6 +29,10 @@
 #define REG_PIN_47_SEL	0x08
 #define REG_FILTER_SEL	0x0c
 
+#if defined(CONFIG_ARCH_MESON_ODROID_COMMON)
+static struct mbox_chan *mbox_chan = NULL;
+#endif
+
 /* use for A1 like chips */
 #define REG_PIN_A1_SEL	0x04
 
@@ -929,6 +936,12 @@
 	platform_set_drvdata(pdev, ctl);
 #endif /* CONFIG_AMLOGIC_MODIFY */
 
+#if defined(CONFIG_ARCH_MESON_ODROID_COMMON)
+	mbox_chan = aml_mbox_request_channel_byidx(irq_dev, 0);
+	if (IS_ERR_OR_NULL(mbox_chan))
+		mbox_chan = NULL;
+#endif
+
 	return 0;
 
 free_channel_irqs:
@@ -982,6 +995,38 @@
 };
 #endif /* CONFIG_AMLOGIC_MODIFY */
 
+#if defined(CONFIG_ARCH_MESON_ODROID_COMMON)
+int irq_meson_gpio_suspend(struct irq_desc *desc, int on)
+{
+	struct irq_data *data;
+	u32 *channel_hwirq;
+	u32 buf[4];
+
+	if (on) {
+		if (!desc)
+			return 0;
+
+		data = &desc->irq_data;
+		channel_hwirq = irq_data_get_irq_chip_data(data);
+		if (*channel_hwirq == 0)
+			return -EINVAL;
+
+		buf[0] = 151 + data->hwirq;
+		buf[1] = 1;             // Currently support LOW only
+		buf[2] = (1 << 0);      // EVENT_SHORT
+		buf[3] = 2;		// DUMMY
+	} else {
+		buf[0] = 0xffffffff;
+	}
+
+	aml_mbox_transfer_data(mbox_chan, MBOX_CMD_SET_KEYPAD,
+			&buf, sizeof(buf), NULL, 0, MBOX_SYNC);
+
+	return 0;
+}
+EXPORT_SYMBOL(irq_meson_gpio_suspend);
+#endif
+
 static const struct of_device_id meson_gpio_irq_match_table[] = {
 	{ .compatible = "amlogic,meson-gpio-intc" },
 	{}
diff --git a/drivers/gpio/pinctrl/pinctrl-meson-s7d.c b/drivers/gpio/pinctrl/pinctrl-meson-s7d.c
index 3f4c2b8..5cfefdc 100644
--- a/drivers/gpio/pinctrl/pinctrl-meson-s7d.c
+++ b/drivers/gpio/pinctrl/pinctrl-meson-s7d.c
@@ -1386,11 +1386,47 @@
 	{ },
 };
 
+#if defined(CONFIG_ARCH_MESON_ODROID_COMMON)
+extern int irq_meson_gpio_suspend(struct irq_desc *desc, int on);
+
+static void meson_pinctrl_shutdown(struct platform_device *pdev)
+{
+	int i, j;
+
+	for (i = 0; i < ARRAY_SIZE(meson_s7d_periphs_banks); i++) {
+		struct meson_bank *bank = &meson_s7d_periphs_banks[i];
+		for (j = bank->irq_first; j <= bank->irq_last; j++) {
+			struct irq_desc *desc = irq_to_desc(j);
+			irq_meson_gpio_suspend(desc, 1);
+		}
+	}
+}
+
+static int meson_pinctrl_suspend(struct platform_device *pdev,
+		pm_message_t state)
+{
+	meson_pinctrl_shutdown(pdev);
+	return 0;
+}
+
+static int meson_pinctrl_resume(struct platform_device *pdev)
+{
+	irq_meson_gpio_suspend(NULL, 0);
+
+	return 0;
+}
+#endif
+
 static struct platform_driver meson_s7d_pinctrl_driver = {
 	.probe  = meson_pinctrl_probe,
 	.driver = {
 		.name	= "meson-s7d-pinctrl",
 	},
+#if defined(CONFIG_ARCH_MESON_ODROID_COMMON)
+	.suspend = meson_pinctrl_suspend,
+	.resume = meson_pinctrl_resume,
+	.shutdown = meson_pinctrl_shutdown,
+#endif
 };
 
 #ifndef MODULE
diff --git a/include/linux/amlogic/aml_mbox_cmd.h b/include/linux/amlogic/aml_mbox_cmd.h
index 90b6102..11c4b4b 100644
--- a/include/linux/amlogic/aml_mbox_cmd.h
+++ b/include/linux/amlogic/aml_mbox_cmd.h
@@ -71,6 +71,7 @@
 #define CMD_BL4_WAIT_UNLOCK	0xD6
 #define CMD_BL4_SEND		0xD7
 #define CMD_BL4_LISTEN		0xD8
+#define CMD_SET_KEYPAD          0xF6
 #define CMD_LEDS_STATE		0xF7
 #define CMD_SET_IR_STATE	0xF8
 #define	CMD_SET_FD650		0x68
@@ -137,6 +138,7 @@
 #define MBOX_CMD_BL4_WAIT_UNLOCK	__MBX_COMPOSE_MSG(MBX_SYSTEM, CMD_BL4_WAIT_UNLOCK)
 #define MBOX_CMD_BL4_SEND		__MBX_COMPOSE_MSG(MBX_SYSTEM, CMD_BL4_SEND)
 #define MBOX_CMD_BL4_LISTEN		__MBX_COMPOSE_MSG(MBX_SYSTEM, CMD_BL4_LISTEN)
+#define MBOX_CMD_SET_KEYPAD		__MBX_COMPOSE_MSG(MBX_SYSTEM, CMD_SET_KEYPAD)
 #define MBOX_CMD_LEDS_STATE		__MBX_COMPOSE_MSG(MBX_SYSTEM, CMD_LEDS_STATE)
 #define MBOX_CMD_SET_IR_STATE		__MBX_COMPOSE_MSG(MBX_SYSTEM, CMD_SET_IR_STATE)
 #define MBOX_CMD_SET_FD650		__MBX_COMPOSE_MSG(MBX_SYSTEM, CMD_SET_FD650)