From 83ffbaceffed1cd47a6f67fb20e39737dfb2d01a Mon Sep 17 00:00:00 2001
From: Frank Wunderlich <frank-w@public-files.de>
Date: Tue, 28 Aug 2018 18:14:56 +0200
Subject: [PATCH] [wifi] adding wifi-related changes outside driver-directory

---
 arch/arm/boot/dts/mt7623.dtsi                 |  41 +-
 arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts |  42 ++
 drivers/soc/mediatek/mtk-pmic-wrap.c          |  12 +
 drivers/watchdog/mtk_wdt.c                    | 377 +++++++++++++++++-
 include/linux/wakelock.h                      |  67 ++++
 include/net/genetlink.h                       |  44 ++
 include/soc/mediatek/pmic_wrap.h              |  19 +
 include/uapi/linux/genetlink.h                |   1 +
 8 files changed, 588 insertions(+), 15 deletions(-)
 create mode 100644 include/linux/wakelock.h
 create mode 100644 include/soc/mediatek/pmic_wrap.h

diff --git a/arch/arm/boot/dts/mt7623.dtsi b/arch/arm/boot/dts/mt7623.dtsi
index 04228cf9ddbbc..af6b6228f8a80 100644
--- a/arch/arm/boot/dts/mt7623.dtsi
+++ b/arch/arm/boot/dts/mt7623.dtsi
@@ -266,6 +266,8 @@
 		compatible = "mediatek,mt7623-wdt",
 			     "mediatek,mt6589-wdt";
 		reg = <0 0x10007000 0 0x100>;
+		interrupts = <GIC_SPI 88 IRQ_TYPE_EDGE_FALLING>;
+		#reset-cells = <1>;
 	};
 
 	timer: timer@10008000 {
@@ -494,13 +496,26 @@
 			     "mediatek,mtk-btif";
 		reg = <0 0x1100c000 0 0x1000>;
 		interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_LOW>;
-		clocks = <&pericfg CLK_PERI_BTIF>;
-		clock-names = "main";
+		clocks = <&pericfg CLK_PERI_BTIF>, <&pericfg CLK_PERI_AP_DMA>;
+		clock-names = "main", "apdmac";
 		reg-shift = <2>;
 		reg-io-width = <4>;
 		status = "disabled";
 	};
 
+	btif_tx: btif_tx@11000780 {
+		compatible = "mediatek,btif_tx";
+		reg = <0 0x11000780 0 0x80>;
+		interrupts = <GIC_SPI 71 IRQ_TYPE_LEVEL_LOW>;
+		status = "okay";
+	};
+	btif_rx: btif_rx@11000800 {
+		compatible = "mediatek,btif_rx";
+		reg = <0 0x11000800 0 0x80>;
+		interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_LOW>;
+		status = "okay";
+	};
+
 	nandc: nfi@1100d000 {
 		compatible = "mediatek,mt7623-nfc",
 			     "mediatek,mt2701-nfc";
@@ -683,6 +698,28 @@
 		status = "disabled";
 	};
 
+	consys: consys@18070000 {
+		compatible = "mediatek,mt7623-consys";
+		reg = <0 0x18070000 0 0x0200>,  /*CONN_MCU_CONFIG_BASE      */
+			<0 0x10001000 0 0x1600>;  /*TOPCKGEN_BASE             */
+		clocks = <&infracfg CLK_INFRA_CONNMCU>;
+		clock-names = "consysbus";
+		power-domains = <&scpsys MT2701_POWER_DOMAIN_CONN>;
+		interrupts = <GIC_SPI 185 IRQ_TYPE_LEVEL_LOW>,  /* BGF_EINT */
+					<GIC_SPI 163 IRQ_TYPE_LEVEL_LOW>;  /* WDT_EINT */
+		resets = <&watchdog MT2701_TOPRGU_CONN_MCU_RST>;
+		reset-names = "connsys";
+		status="disabled";
+	};
+	wifi:wifi@180f0000 {
+		compatible = "mediatek,mt7623-wifi",
+					"mediatek,wifi";
+		reg = <0 0x180f0000 0 0x005c>;
+		interrupts = <GIC_SPI 184 IRQ_TYPE_LEVEL_LOW>;
+		clocks = <&pericfg CLK_PERI_AP_DMA>;
+		clock-names = "wifi-dma";
+	};
+
 	hifsys: syscon@1a000000 {
 		compatible = "mediatek,mt7623-hifsys",
 			     "mediatek,mt2701-hifsys",
diff --git a/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts b/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts
index 2b760f90f38c8..465fb887b2ca6 100644
--- a/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts
+++ b/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts
@@ -84,6 +84,18 @@
 		};
 	};
 
+	reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+		consys-reserve-memory {
+			compatible = "mediatek,consys-reserve-memory";
+			no-map;
+			size = <0 0x100000>;
+			alignment = <0 0x100000>;
+		};
+	};
+
 	leds {
 		compatible = "gpio-leds";
 		pinctrl-names = "default";
@@ -259,6 +271,36 @@
 	};
 };
 
+&pio {
+	consys_pins_default: consys_pins_default {
+		adie {
+			pinmux = <MT7623_PIN_60_WB_RSTB_FUNC_WB_RSTB>,
+				<MT7623_PIN_61_GPIO61_FUNC_TEST_FD>,
+				<MT7623_PIN_62_GPIO62_FUNC_TEST_FC>,
+				<MT7623_PIN_63_WB_SCLK_FUNC_WB_SCLK>,
+				<MT7623_PIN_64_WB_SDATA_FUNC_WB_SDATA>,
+				<MT7623_PIN_65_WB_SEN_FUNC_WB_SEN>,
+				<MT7623_PIN_66_WB_CRTL0_FUNC_WB_CRTL0>,
+				<MT7623_PIN_67_WB_CRTL1_FUNC_WB_CRTL1>,
+				<MT7623_PIN_68_WB_CRTL2_FUNC_WB_CRTL2>,
+				<MT7623_PIN_69_WB_CRTL3_FUNC_WB_CRTL3>,
+				<MT7623_PIN_70_WB_CRTL4_FUNC_WB_CRTL4>,
+				<MT7623_PIN_71_WB_CRTL5_FUNC_WB_CRTL5>;
+				bias-disable;
+		};
+	};
+};
+&consys {
+	mediatek,pwrap-regmap = <&pwrap>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&consys_pins_default>;
+	vcn18-supply = <&mt6323_vcn18_reg>;
+	vcn28-supply = <&mt6323_vcn28_reg>;
+	vcn33_bt-supply = <&mt6323_vcn33_bt_reg>;
+	vcn33_wifi-supply = <&mt6323_vcn33_wifi_reg>;
+	status = "okay";
+};
+
 &pcie {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pcie_default>;
diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c
index 4e931fdf4d091..6600396ee2993 100644
--- a/drivers/soc/mediatek/mtk-pmic-wrap.c
+++ b/drivers/soc/mediatek/mtk-pmic-wrap.c
@@ -1530,6 +1530,18 @@ static const struct of_device_id of_pwrap_match_tbl[] = {
 };
 MODULE_DEVICE_TABLE(of, of_pwrap_match_tbl);
 
+struct regmap *pwrap_node_to_regmap(struct device_node *np)
+{
+	struct platform_device *pdev;
+	struct pmic_wrapper *wrp;
+	pdev = of_find_device_by_node(np);
+	if (!pdev)
+		return ERR_PTR(-ENODEV);
+	wrp = platform_get_drvdata(pdev);
+	return wrp->regmap;
+}
+EXPORT_SYMBOL_GPL(pwrap_node_to_regmap);
+
 static int pwrap_probe(struct platform_device *pdev)
 {
 	int ret, irq;
diff --git a/drivers/watchdog/mtk_wdt.c b/drivers/watchdog/mtk_wdt.c
index 4baf64f21aa11..6a361f808aed1 100644
--- a/drivers/watchdog/mtk_wdt.c
+++ b/drivers/watchdog/mtk_wdt.c
@@ -1,4 +1,3 @@
-// SPDX-License-Identifier: GPL-2.0+
 /*
  * Mediatek Watchdog Driver
  *
@@ -6,20 +5,51 @@
  *
  * Matthias Brugger <matthias.bgg@gmail.com>
  *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
  * Based on sunxi_wdt.c
  */
 
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/uaccess.h>
 #include <linux/of.h>
+#include <linux/of_irq.h>
 #include <linux/platform_device.h>
+#ifdef CONFIG_FIQ_GLUE
+#include <linux/irqchip/mtk-gic-extend.h>
+#include <mt-plat/aee.h>
+#endif
 #include <linux/types.h>
 #include <linux/watchdog.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
 #include <linux/delay.h>
+#include <linux/reset-controller.h>
+#include <linux/reset.h>
+#include <linux/sched.h>
+#include <linux/sched/debug.h>
+#include <linux/sched/signal.h>
+#include <asm/system_misc.h>
+#include <linux/seq_file.h>
+#ifdef CONFIG_MT6397_MISC
+#include <linux/mfd/mt6397/rtc_misc.h>
+#endif
 
 #define WDT_MAX_TIMEOUT		31
 #define WDT_MIN_TIMEOUT		1
@@ -38,37 +68,167 @@
 #define WDT_MODE_EXRST_EN	(1 << 2)
 #define WDT_MODE_IRQ_EN		(1 << 3)
 #define WDT_MODE_AUTO_START	(1 << 4)
+#define WDT_MODE_IRQ_LVL	(1 << 5)
 #define WDT_MODE_DUAL_EN	(1 << 6)
 #define WDT_MODE_KEY		0x22000000
 
+#define WDT_STATUS		0x0c
+#define WDT_NONRST_REG		0x20
+#define WDT_NONRST_REG2		0x24
+
 #define WDT_SWRST		0x14
 #define WDT_SWRST_KEY		0x1209
 
+#define WDT_SWSYSRST		0x18
+#define WDT_SWSYSRST_KEY	0x88000000
+
+#define WDT_REQ_MODE 0x30
+#define WDT_REQ_MODE_KEY 0x33000000
+#define WDT_REQ_IRQ_EN 0x34
+#define WDT_REQ_IRQ_KEY 0x44000000
+#define WDT_REQ_MODE_DEBUG_EN 0x80000
+
+
 #define DRV_NAME		"mtk-wdt"
-#define DRV_VERSION		"1.0"
+#define DRV_VERSION		"2.0"
 
 static bool nowayout = WATCHDOG_NOWAYOUT;
-static unsigned int timeout;
+static unsigned int timeout = WDT_MAX_TIMEOUT;
+
+struct toprgu_reset {
+	spinlock_t lock;
+	void __iomem *toprgu_swrst_base;
+	int regofs;
+	struct reset_controller_dev rcdev;
+};
 
 struct mtk_wdt_dev {
 	struct watchdog_device wdt_dev;
 	void __iomem *wdt_base;
+	int wdt_irq_id;
+	struct notifier_block restart_handler;
+	struct toprgu_reset reset_controller;
 };
 
-static int mtk_wdt_restart(struct watchdog_device *wdt_dev,
-			   unsigned long action, void *data)
+static void __iomem *toprgu_base;
+static struct watchdog_device *wdt_dev;
+
+static int toprgu_reset_assert(struct reset_controller_dev *rcdev,
+			      unsigned long id)
 {
-	struct mtk_wdt_dev *mtk_wdt = watchdog_get_drvdata(wdt_dev);
+	unsigned int tmp;
+	unsigned long flags;
+	struct toprgu_reset *data = container_of(rcdev, struct toprgu_reset, rcdev);
+
+	spin_lock_irqsave(&data->lock, flags);
+
+	tmp = __raw_readl(data->toprgu_swrst_base + data->regofs);
+	tmp |= BIT(id);
+	tmp |= WDT_SWSYSRST_KEY;
+	writel(tmp, data->toprgu_swrst_base + data->regofs);
+
+	spin_unlock_irqrestore(&data->lock, flags);
+
+	return 0;
+}
+
+static int toprgu_reset_deassert(struct reset_controller_dev *rcdev,
+				unsigned long id)
+{
+	unsigned int tmp;
+	unsigned long flags;
+	struct toprgu_reset *data = container_of(rcdev, struct toprgu_reset, rcdev);
+
+	spin_lock_irqsave(&data->lock, flags);
+
+	tmp = __raw_readl(data->toprgu_swrst_base + data->regofs);
+	tmp &= ~BIT(id);
+	tmp |= WDT_SWSYSRST_KEY;
+	writel(tmp, data->toprgu_swrst_base + data->regofs);
+
+	spin_unlock_irqrestore(&data->lock, flags);
+
+	return 0;
+}
+
+static int toprgu_reset(struct reset_controller_dev *rcdev,
+			      unsigned long id)
+{
+	int ret;
+
+	ret = toprgu_reset_assert(rcdev, id);
+	if (ret)
+		return ret;
+
+	return toprgu_reset_deassert(rcdev, id);
+}
+
+static struct reset_control_ops toprgu_reset_ops = {
+	.assert = toprgu_reset_assert,
+	.deassert = toprgu_reset_deassert,
+	.reset = toprgu_reset,
+};
+
+static void toprgu_register_reset_controller(struct platform_device *pdev, int regofs)
+{
+	int ret;
+	struct mtk_wdt_dev *mtk_wdt = platform_get_drvdata(pdev);
+
+	spin_lock_init(&mtk_wdt->reset_controller.lock);
+
+	mtk_wdt->reset_controller.toprgu_swrst_base = mtk_wdt->wdt_base;
+	mtk_wdt->reset_controller.regofs = regofs;
+	mtk_wdt->reset_controller.rcdev.owner = THIS_MODULE;
+	mtk_wdt->reset_controller.rcdev.nr_resets = 15;
+	mtk_wdt->reset_controller.rcdev.ops = &toprgu_reset_ops;
+	mtk_wdt->reset_controller.rcdev.of_node = pdev->dev.of_node;
+
+	ret = reset_controller_register(&mtk_wdt->reset_controller.rcdev);
+	if (ret)
+		pr_err("could not register toprgu reset controller: %d\n", ret);
+}
+
+static int mtk_reset_handler(struct notifier_block *this, unsigned long mode,
+				void *cmd)
+{
+	struct mtk_wdt_dev *mtk_wdt;
 	void __iomem *wdt_base;
+	u32 reg;
 
+	mtk_wdt = container_of(this, struct mtk_wdt_dev, restart_handler);
 	wdt_base = mtk_wdt->wdt_base;
 
-	while (1) {
-		writel(WDT_SWRST_KEY, wdt_base + WDT_SWRST);
-		mdelay(5);
+	/* WDT_STATUS will be cleared to  zero after writing to WDT_MODE, so we backup it in WDT_NONRST_REG,
+	  * and then print it out in mtk_wdt_probe() after reset
+	  */
+	writel(__raw_readl(wdt_base + WDT_STATUS), wdt_base + WDT_NONRST_REG);
+
+	reg = ioread32(wdt_base + WDT_MODE);
+	reg &= ~(WDT_MODE_DUAL_EN | WDT_MODE_IRQ_EN | WDT_MODE_EN);
+	reg |= WDT_MODE_KEY;
+	iowrite32(reg, wdt_base + WDT_MODE);
+
+	if (cmd && !strcmp(cmd, "rpmbpk")) {
+		iowrite32(ioread32(wdt_base + WDT_NONRST_REG2) | (1 << 0), wdt_base + WDT_NONRST_REG2);
+	} else if (cmd && !strcmp(cmd, "recovery")) {
+		iowrite32(ioread32(wdt_base + WDT_NONRST_REG2) | (1 << 1), wdt_base + WDT_NONRST_REG2);
+		#ifdef CONFIG_MT6397_MISC
+		mtk_misc_mark_recovery();
+		#endif
+	} else if (cmd && !strcmp(cmd, "bootloader")) {
+		iowrite32(ioread32(wdt_base + WDT_NONRST_REG2) | (1 << 2), wdt_base + WDT_NONRST_REG2);
+		#ifdef CONFIG_MT6397_MISC
+		mtk_misc_mark_fast();
+		#endif
 	}
 
-	return 0;
+	if (!arm_pm_restart) {
+		while (1) {
+			writel(WDT_SWRST_KEY, wdt_base + WDT_SWRST);
+			mdelay(5);
+		}
+	}
+	return NOTIFY_DONE;
 }
 
 static int mtk_wdt_ping(struct watchdog_device *wdt_dev)
@@ -77,6 +237,7 @@ static int mtk_wdt_ping(struct watchdog_device *wdt_dev)
 	void __iomem *wdt_base = mtk_wdt->wdt_base;
 
 	iowrite32(WDT_RST_RELOAD, wdt_base + WDT_RST);
+	printk_deferred("[WDK]: kick Ex WDT\n");
 
 	return 0;
 }
@@ -128,7 +289,8 @@ static int mtk_wdt_start(struct watchdog_device *wdt_dev)
 		return ret;
 
 	reg = ioread32(wdt_base + WDT_MODE);
-	reg &= ~(WDT_MODE_IRQ_EN | WDT_MODE_DUAL_EN);
+	reg |= (WDT_MODE_DUAL_EN | WDT_MODE_IRQ_EN | WDT_MODE_EXRST_EN);
+	reg &= ~(WDT_MODE_IRQ_LVL | WDT_MODE_EXT_POL_HIGH);
 	reg |= (WDT_MODE_EN | WDT_MODE_KEY);
 	iowrite32(reg, wdt_base + WDT_MODE);
 
@@ -148,13 +310,56 @@ static const struct watchdog_ops mtk_wdt_ops = {
 	.stop		= mtk_wdt_stop,
 	.ping		= mtk_wdt_ping,
 	.set_timeout	= mtk_wdt_set_timeout,
-	.restart	= mtk_wdt_restart,
 };
 
+#ifdef CONFIG_FIQ_GLUE
+static void wdt_fiq(void *arg, void *regs, void *svc_sp)
+{
+	unsigned int wdt_mode_val;
+	void __iomem *wdt_base = ((struct mtk_wdt_dev *)arg)->wdt_base;
+
+	wdt_mode_val = __raw_readl(wdt_base + WDT_STATUS);
+	writel(wdt_mode_val, wdt_base + WDT_NONRST_REG);
+
+	aee_wdt_fiq_info(arg, regs, svc_sp);
+}
+#else
+static void wdt_report_info(void)
+{
+	struct task_struct *task;
+
+	task = &init_task;
+	pr_debug("Qwdt: -- watchdog time out\n");
+
+	for_each_process(task) {
+		if (task->state == 0) {
+			pr_debug("PID: %d, name: %s\n backtrace:\n", task->pid, task->comm);
+			show_stack(task, NULL);
+			pr_debug("\n");
+		}
+	}
+
+	pr_debug("backtrace of current task:\n");
+	show_stack(NULL, NULL);
+	pr_debug("Qwdt: -- watchdog time out\n");
+}
+
+static irqreturn_t mtk_wdt_isr(int irq, void *dev_id)
+{
+	pr_err("fwq mtk_wdt_isr\n");
+
+	wdt_report_info();
+	BUG();
+
+	return IRQ_HANDLED;
+}
+#endif
+
 static int mtk_wdt_probe(struct platform_device *pdev)
 {
 	struct mtk_wdt_dev *mtk_wdt;
 	struct resource *res;
+	unsigned int tmp;
 	int err;
 
 	mtk_wdt = devm_kzalloc(&pdev->dev, sizeof(*mtk_wdt), GFP_KERNEL);
@@ -165,9 +370,32 @@ static int mtk_wdt_probe(struct platform_device *pdev)
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	mtk_wdt->wdt_base = devm_ioremap_resource(&pdev->dev, res);
+
 	if (IS_ERR(mtk_wdt->wdt_base))
 		return PTR_ERR(mtk_wdt->wdt_base);
 
+	pr_err("MTK_WDT_NONRST_REG(%x)\n", __raw_readl(mtk_wdt->wdt_base + WDT_NONRST_REG));
+
+	mtk_wdt->wdt_irq_id = irq_of_parse_and_map(pdev->dev.of_node, 0);
+	if (!mtk_wdt->wdt_irq_id) {
+		pr_err("RGU get IRQ ID failed\n");
+		return -ENODEV;
+	}
+
+#ifndef CONFIG_FIQ_GLUE
+	err = request_irq(mtk_wdt->wdt_irq_id, (irq_handler_t)mtk_wdt_isr, IRQF_TRIGGER_NONE, DRV_NAME, mtk_wdt);
+#else
+	mtk_wdt->wdt_irq_id = get_hardware_irq(mtk_wdt->wdt_irq_id);
+	err = request_fiq(mtk_wdt->wdt_irq_id, wdt_fiq, IRQF_TRIGGER_FALLING, mtk_wdt);
+#endif
+	if (err != 0) {
+		pr_err("mtk_wdt_probe : failed to request irq (%d)\n", err);
+		return err;
+	}
+
+	toprgu_base = mtk_wdt->wdt_base;
+	wdt_dev = &mtk_wdt->wdt_dev;
+
 	mtk_wdt->wdt_dev.info = &mtk_wdt_info;
 	mtk_wdt->wdt_dev.ops = &mtk_wdt_ops;
 	mtk_wdt->wdt_dev.timeout = WDT_MAX_TIMEOUT;
@@ -177,7 +405,6 @@ static int mtk_wdt_probe(struct platform_device *pdev)
 
 	watchdog_init_timeout(&mtk_wdt->wdt_dev, timeout, &pdev->dev);
 	watchdog_set_nowayout(&mtk_wdt->wdt_dev, nowayout);
-	watchdog_set_restart_priority(&mtk_wdt->wdt_dev, 128);
 
 	watchdog_set_drvdata(&mtk_wdt->wdt_dev, mtk_wdt);
 
@@ -187,9 +414,40 @@ static int mtk_wdt_probe(struct platform_device *pdev)
 	if (unlikely(err))
 		return err;
 
+	mtk_wdt->restart_handler.notifier_call = mtk_reset_handler;
+	mtk_wdt->restart_handler.priority = 128;
+
+	if (arm_pm_restart) {
+		dev_info(&pdev->dev, "register restart_handler on reboot_notifier_list for psci reset\n");
+		err = register_reboot_notifier(&mtk_wdt->restart_handler);
+		if (err != 0)
+			dev_warn(&pdev->dev,
+				"cannot register reboot notifier (err=%d)\n", err);
+	} else {
+		err = register_restart_handler(&mtk_wdt->restart_handler);
+		if (err)
+			dev_warn(&pdev->dev,
+				"cannot register restart handler (err=%d)\n", err);
+	}
+
 	dev_info(&pdev->dev, "Watchdog enabled (timeout=%d sec, nowayout=%d)\n",
 			mtk_wdt->wdt_dev.timeout, nowayout);
 
+	writel(WDT_REQ_MODE_KEY | (__raw_readl(mtk_wdt->wdt_base + WDT_REQ_MODE) &
+		(~WDT_REQ_MODE_DEBUG_EN)), mtk_wdt->wdt_base + WDT_REQ_MODE);
+
+	toprgu_register_reset_controller(pdev, WDT_SWSYSRST);
+
+	/* enable scpsys thermal and thermal_controller request, and set to reset directly mode */
+	tmp = ioread32(mtk_wdt->wdt_base + WDT_REQ_MODE) | (1 << 18) | (1 << 0);
+	tmp |= WDT_REQ_MODE_KEY;
+	iowrite32(tmp, mtk_wdt->wdt_base + WDT_REQ_MODE);
+
+	tmp = ioread32(mtk_wdt->wdt_base + WDT_REQ_IRQ_EN);
+	tmp &= ~((1 << 18) | (1 << 0));
+	tmp |= WDT_REQ_IRQ_KEY;
+	iowrite32(tmp, mtk_wdt->wdt_base + WDT_REQ_IRQ_EN);
+
 	return 0;
 }
 
@@ -205,8 +463,12 @@ static int mtk_wdt_remove(struct platform_device *pdev)
 {
 	struct mtk_wdt_dev *mtk_wdt = platform_get_drvdata(pdev);
 
+	unregister_restart_handler(&mtk_wdt->restart_handler);
+
 	watchdog_unregister_device(&mtk_wdt->wdt_dev);
 
+	reset_controller_unregister(&mtk_wdt->reset_controller.rcdev);
+
 	return 0;
 }
 
@@ -258,6 +520,95 @@ static struct platform_driver mtk_wdt_driver = {
 
 module_platform_driver(mtk_wdt_driver);
 
+static int wk_proc_cmd_read(struct seq_file *s, void *v)
+{
+	unsigned int enabled = 1;
+
+	if (!(ioread32(toprgu_base + WDT_MODE) & WDT_MODE_EN))
+		enabled = 0;
+
+	seq_printf(s, "enabled timeout\n%-4d %-8d\n", enabled, wdt_dev->timeout);
+
+	return 0;
+}
+
+static int wk_proc_cmd_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, wk_proc_cmd_read, NULL);
+}
+
+static ssize_t wk_proc_cmd_write(struct file *file, const char *buf, size_t count, loff_t *data)
+{
+	int ret;
+	int enable;
+	int timeout;
+	char wk_cmd_buf[256];
+
+	if (count == 0)
+		return -1;
+
+	if (count > 255)
+		count = 255;
+
+	ret = copy_from_user(wk_cmd_buf, buf, count);
+	if (ret < 0)
+		return -1;
+
+	wk_cmd_buf[count] = '\0';
+
+	pr_debug("Write %s\n", wk_cmd_buf);
+
+	ret = sscanf(wk_cmd_buf, "%d %d", &enable, &timeout);
+	if (ret != 2)
+		pr_debug("%s: expect 2 numbers\n", __func__);
+
+	pr_debug("[WDK] enable=%d  timeout=%d\n", enable, timeout);
+
+	if (timeout > 20 && timeout <= WDT_MAX_TIMEOUT) {
+		wdt_dev->timeout = timeout;
+		mtk_wdt_set_timeout(wdt_dev, wdt_dev->timeout);
+	} else {
+		pr_err("[WDK] The timeout(%d) should bigger than 20 and not bigger than %d\n",
+				timeout, WDT_MAX_TIMEOUT);
+
+	}
+
+	if (enable == 1) {
+		mtk_wdt_start(wdt_dev);
+		set_bit(WDOG_ACTIVE, &wdt_dev->status);
+		pr_err("[WDK] enable wdt\n");
+	} else if (enable == 0) {
+		mtk_wdt_stop(wdt_dev);
+		clear_bit(WDOG_ACTIVE, &wdt_dev->status);
+		pr_err("[WDK] disable wdt\n");
+	}
+
+	return count;
+}
+
+static const struct file_operations wk_proc_cmd_fops = {
+	.owner = THIS_MODULE,
+	.open = wk_proc_cmd_open,
+	.read = seq_read,
+	.write = wk_proc_cmd_write,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static int __init wk_proc_init(void)
+{
+	struct proc_dir_entry *de = proc_create("wdk", 0660, NULL, &wk_proc_cmd_fops);
+
+	if (!de)
+		pr_err("[wk_proc_init]: create /proc/wdk failed\n");
+
+	pr_debug("[WDK] Initialize proc\n");
+
+	return 0;
+}
+
+late_initcall(wk_proc_init);
+
 module_param(timeout, uint, 0);
 MODULE_PARM_DESC(timeout, "Watchdog heartbeat in seconds");
 
diff --git a/include/linux/wakelock.h b/include/linux/wakelock.h
new file mode 100644
index 0000000000000..f4a698a228803
--- /dev/null
+++ b/include/linux/wakelock.h
@@ -0,0 +1,67 @@
+/* include/linux/wakelock.h
+ *
+ * Copyright (C) 2007-2012 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _LINUX_WAKELOCK_H
+#define _LINUX_WAKELOCK_H
+
+#include <linux/ktime.h>
+#include <linux/device.h>
+
+/* A wake_lock prevents the system from entering suspend or other low power
+ * states when active. If the type is set to WAKE_LOCK_SUSPEND, the wake_lock
+ * prevents a full system suspend.
+ */
+
+enum {
+	WAKE_LOCK_SUSPEND, /* Prevent suspend */
+	WAKE_LOCK_TYPE_COUNT
+};
+
+struct wake_lock {
+	struct wakeup_source ws;
+};
+
+static inline void wake_lock_init(struct wake_lock *lock, int type,
+				  const char *name)
+{
+	wakeup_source_init(&lock->ws, name);
+}
+
+static inline void wake_lock_destroy(struct wake_lock *lock)
+{
+	wakeup_source_trash(&lock->ws);
+}
+
+static inline void wake_lock(struct wake_lock *lock)
+{
+	__pm_stay_awake(&lock->ws);
+}
+
+static inline void wake_lock_timeout(struct wake_lock *lock, long timeout)
+{
+	__pm_wakeup_event(&lock->ws, jiffies_to_msecs(timeout));
+}
+
+static inline void wake_unlock(struct wake_lock *lock)
+{
+	__pm_relax(&lock->ws);
+}
+
+static inline int wake_lock_active(struct wake_lock *lock)
+{
+	return lock->ws.active;
+}
+
+#endif
diff --git a/include/net/genetlink.h b/include/net/genetlink.h
index decf6012a4016..6471da92334ad 100644
--- a/include/net/genetlink.h
+++ b/include/net/genetlink.h
@@ -144,6 +144,50 @@ struct genl_ops {
 };
 
 int genl_register_family(struct genl_family *family);
+
+/**
+ * genl_register_family_with_ops - register a generic netlink family with ops
+ * @family: generic netlink family
+ * @ops: operations to be registered
+ * @n_ops: number of elements to register
+ *
+ * Registers the specified family and operations from the specified table.
+ * Only one family may be registered with the same family name or identifier.
+ *
+ * The family id may equal GENL_ID_GENERATE causing an unique id to
+ * be automatically generated and assigned.
+ *
+ * Either a doit or dumpit callback must be specified for every registered
+ * operation or the function will fail. Only one operation structure per
+ * command identifier may be registered.
+ *
+ * See include/net/genetlink.h for more documenation on the operations
+ * structure.
+ *
+ * Return 0 on success or a negative error code.
+ */
+static inline int
+_genl_register_family_with_ops_grps(struct genl_family *family,
+				    const struct genl_ops *ops, size_t n_ops,
+				    const struct genl_multicast_group *mcgrps,
+				    size_t n_mcgrps)
+{
+	family->module = THIS_MODULE;
+	family->ops = ops;
+	family->n_ops = n_ops;
+	family->mcgrps = mcgrps;
+	family->n_mcgrps = n_mcgrps;
+	return genl_register_family(family);
+}
+#define genl_register_family_with_ops(family, ops)			\
+	_genl_register_family_with_ops_grps((family),			\
+					    (ops), ARRAY_SIZE(ops),	\
+					    NULL, 0)
+#define genl_register_family_with_ops_groups(family, ops, grps)	\
+	_genl_register_family_with_ops_grps((family),			\
+					    (ops), ARRAY_SIZE(ops),	\
+					    (grps), ARRAY_SIZE(grps))
+
 int genl_unregister_family(const struct genl_family *family);
 void genl_notify(const struct genl_family *family, struct sk_buff *skb,
 		 struct genl_info *info, u32 group, gfp_t flags);
diff --git a/include/soc/mediatek/pmic_wrap.h b/include/soc/mediatek/pmic_wrap.h
new file mode 100644
index 0000000000000..5b5c85272c58b
--- /dev/null
+++ b/include/soc/mediatek/pmic_wrap.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2015 MediaTek Inc.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __SOC_MEDIATEK_PMIC_WRAP_H
+#define __SOC_MEDIATEK_PMIC_WRAP_H
+
+extern struct regmap *pwrap_node_to_regmap(struct device_node *np);
+
+#endif /* __SOC_MEDIATEK_PMIC_WRAP_H */
diff --git a/include/uapi/linux/genetlink.h b/include/uapi/linux/genetlink.h
index 877f7fa954666..6a176b3d43f9b 100644
--- a/include/uapi/linux/genetlink.h
+++ b/include/uapi/linux/genetlink.h
@@ -27,6 +27,7 @@ struct genlmsghdr {
 /*
  * List of reserved static generic netlink identifiers:
  */
+#define GENL_ID_GENERATE	0
 #define GENL_ID_CTRL		NLMSG_MIN_TYPE
 #define GENL_ID_VFS_DQUOT	(NLMSG_MIN_TYPE + 1)
 #define GENL_ID_PMCRAID		(NLMSG_MIN_TYPE + 2)
