From 2e1bacff999529c9b91995db5d87ad6708e7d49e Mon Sep 17 00:00:00 2001
From: vpeter4 <peter.vicman@gmail.com>
Date: Wed, 3 Jun 2015 19:09:09 +0200
Subject: [PATCH] Add poweroff driver, enable touchscreen

Use original power_off function from rtc-snvs if set.
Arduino operation is controled by device tree parameter.

From 1bc304cd507fe9eb5673223f0d76ec0aa4ff55f3 Mon Sep 17 00:00:00 2001
From: mxt512 <mtx512@yahoo.co.uk>
Date: Thu, 13 Feb 2014 20:13:27 +0000
Subject: [PATCH] Add poweroff driver.

Existing pm_power_off function was in rtc-snvs. Given we need to reset the SAM3X and turn off
the 5v supply on power down, lets implement a power-off driver to do this for now.

TODO: Not the cleanest solution but it works, should revisit.
      Overwriting power_off function with udoo_power_off in case uddo is used. 

---
 drivers/power/reset/Kconfig         |   8 ++
 drivers/power/reset/Makefile        |   1 +
 drivers/power/reset/udoo-poweroff.c | 159 ++++++++++++++++++++++++++++++++++++
 3 files changed, 168 insertions(+)
 create mode 100644 drivers/power/reset/udoo-poweroff.c

diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig
index 6d452a7..1a0620f 100644
--- a/drivers/power/reset/Kconfig
+++ b/drivers/power/reset/Kconfig
@@ -57,3 +57,11 @@ config POWER_RESET_XGENE
 	depends on POWER_RESET
 	help
 	  Reboot support for the APM SoC X-Gene Eval boards.
+
+config POWER_RESET_UDOO
+	bool "UDOO power-off driver"
+	depends on POWER_RESET
+	help
+	  This driver supports powering down the UDOO.
+	  Say Y if you have a UDOO.
+
diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile
index a5b4a77..9b8e1b0 100644
--- a/drivers/power/reset/Makefile
+++ b/drivers/power/reset/Makefile
@@ -5,3 +5,4 @@ obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o
 obj-$(CONFIG_POWER_RESET_RESTART) += restart-poweroff.o
 obj-$(CONFIG_POWER_RESET_VEXPRESS) += vexpress-poweroff.o
 obj-$(CONFIG_POWER_RESET_XGENE) += xgene-reboot.o
+obj-$(CONFIG_POWER_RESET_UDOO) += udoo-poweroff.o
diff --git a/drivers/power/reset/udoo-poweroff.c b/drivers/power/reset/udoo-poweroff.c
new file mode 100644
index 0000000..b3f8db8
--- /dev/null
+++ b/drivers/power/reset/udoo-poweroff.c
@@ -0,0 +1,159 @@
+/*
+ * UDOO board power off
+ *
+ * Copyright (C) 2014 Jasbir Matharu
+ * Copyright (C) 2015 Peter Vicman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/of_gpio.h>
+
+#define ARDUINO_MODE_STOPPED      1   /* does arduino starts at boot */
+#define ARDUINO_MODE_LEAVE_POWER  2   /* leave 5V power on after shutdown (to keep arduino reset) */
+
+static void (*pm_power_off_orig)(void) = NULL;
+static int sam3x_rst_gpio = -EINVAL;
+static int pwr_5v_gpio = -EINVAL;
+static u32 arduino_mode = -EINVAL;
+static int lcd_touch_reset_gpio = -EINVAL;  
+static int lcd_panel_on_gpio = -EINVAL;
+static int lcd_backlight_gpio = -EINVAL;  
+
+static void udoo_set_gpio(unsigned gpio, int value) {
+	int ret;
+
+  if (! gpio_is_valid(gpio))
+  	return;
+  	
+  ret = gpio_direction_output(gpio, value);
+  if (ret)
+    pr_err("%s: gpio %u/%d failed\n", __func__, gpio, value);
+}
+
+static void udoo_request_gpio(struct device *dev, unsigned gpio, unsigned long flags, const char *label) {
+	int ret;
+
+  if (! gpio_is_valid(gpio))
+  	return;
+  	
+	ret = devm_gpio_request_one(dev, gpio, flags, label);
+	if (ret)
+		dev_err(dev, "request of gpio %s %u failed with %d\n", label, gpio, ret);
+}
+    
+static void udoo_power_off(void) {
+  pr_emerg("%s: powering off\n", __func__);
+  
+  if (pm_power_off_orig != NULL)
+    pm_power_off_orig();
+ 
+  udoo_set_gpio(lcd_touch_reset_gpio, 1);
+  udoo_set_gpio(lcd_panel_on_gpio, 0);
+  udoo_set_gpio(lcd_backlight_gpio, 0);
+  
+  udoo_set_gpio(sam3x_rst_gpio, 0);
+  msleep(50);		/* stop sam3x safely */
+
+  if (gpio_is_valid(pwr_5v_gpio) && (arduino_mode & ARDUINO_MODE_LEAVE_POWER) == 0) {
+    pr_emerg("%s: 5V power down\n", __func__);
+    udoo_set_gpio(pwr_5v_gpio, 1);
+  } else
+  	pr_emerg("%s: 5V power still on, sam3x reset\n", __func__);
+}
+
+static int udoo_power_off_probe(struct platform_device *pdev)
+{
+  struct device_node *pwr_off_np;
+  int ret;
+
+  dev_err(&pdev->dev, "%s: power-off probe\n", __func__);
+
+  pwr_off_np = of_find_compatible_node(NULL, NULL, "sitronix,st1232");
+  if (pwr_off_np) {
+    lcd_touch_reset_gpio = of_get_named_gpio(pwr_off_np, "gpios", 0);
+		lcd_panel_on_gpio = of_get_named_gpio(pwr_off_np, "lcd_panel_on_gpio", 0);
+		lcd_backlight_gpio = of_get_named_gpio(pwr_off_np, "lcd_backlight_gpio", 0);
+    of_node_put(pwr_off_np);
+
+		udoo_request_gpio(&pdev->dev, lcd_panel_on_gpio, GPIOF_OUT_INIT_HIGH, "lcd_panel_on_gpio");
+		udoo_request_gpio(&pdev->dev, lcd_backlight_gpio, GPIOF_OUT_INIT_HIGH, "lcd_backlight_gpio");
+		
+		ret = gpio_export(lcd_backlight_gpio, false);
+  }
+  
+  pwr_off_np = of_find_compatible_node(NULL, NULL, "udoo,poweroff");
+  if (pwr_off_np) {
+    ret = of_property_read_u32(pwr_off_np, "arduino_mode", &arduino_mode);
+    if (ret != 0) {
+      dev_err(&pdev->dev, "%s: arduino mode not found in dtb\n", __func__);
+      arduino_mode = 0;
+    }
+
+    sam3x_rst_gpio = of_get_named_gpio(pwr_off_np, "sam3x_rst_gpio", 0);
+    pwr_5v_gpio = of_get_named_gpio(pwr_off_np, "pwr_5v_gpio", 0);
+    of_node_put(pwr_off_np);
+
+		udoo_request_gpio(&pdev->dev, pwr_5v_gpio, GPIOF_OUT_INIT_LOW, "pwr_5v_gpio");
+	
+  	if (gpio_is_valid(sam3x_rst_gpio)) {
+  		ret = gpio_export(sam3x_rst_gpio, false);
+		
+  	  if (arduino_mode & ARDUINO_MODE_STOPPED) {
+  	    dev_err(&pdev->dev, "%s: arduino stopped\n", __func__);
+  	    udoo_set_gpio(sam3x_rst_gpio, 0);
+  	  } else {
+  	  	dev_err(&pdev->dev, "%s: arduino running\n", __func__);
+  	    udoo_set_gpio(sam3x_rst_gpio, 1);
+  	  }
+  	}
+
+    pm_power_off_orig = pm_power_off;
+    pm_power_off = udoo_power_off;
+    return 0;
+  }
+
+  /* If a pm_power_off function has already been added, leave it alone */
+  if (pm_power_off != NULL) {
+    dev_err(&pdev->dev, "%s: pm_power_off function already registered\n", __func__);
+    return -EBUSY;
+  }
+
+  return -ENODEV;
+}
+
+static int udoo_power_off_remove(struct platform_device *pdev)
+{
+  return 0;
+}
+
+static const struct of_device_id power_off_dt_ids[] = {
+  { .compatible = "udoo,poweroff", },
+  { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, power_off_dt_ids);
+
+static struct platform_driver udoo_power_off_driver = {
+  .driver = {
+    .name = "udoo_power_off",
+    .owner  = THIS_MODULE,
+    .of_match_table = of_match_ptr(power_off_dt_ids),
+  },
+  .probe    = udoo_power_off_probe,
+  .remove   = udoo_power_off_remove,
+};
+module_platform_driver(udoo_power_off_driver);
+
+MODULE_AUTHOR("Jasbir Matharu, Peter Vicman");
+MODULE_DESCRIPTION("UDOO Power off driver v3");
+MODULE_LICENSE("GPL v2");
-- 
1.8.1.2
