build/patch/kernel/archive/mt7623-4.19/0002-r2-wifi-add-dt.patch

843 lines
24 KiB
Diff
Raw Permalink Normal View History

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)