mirror of
				https://github.com/Ysurac/openmptcprouter.git
				synced 2025-03-09 15:40:20 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			846 lines
		
	
	
	
		
			24 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			846 lines
		
	
	
	
		
			24 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| 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 07/77] [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 04228cf9ddbb..af6b6228f8a8 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 2b760f90f38c..465fb887b2ca 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 4e931fdf4d09..6600396ee299 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 4baf64f21aa1..6a361f808aed 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 000000000000..f4a698a22880
 | |
| --- /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 decf6012a401..6471da92334a 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 000000000000..5b5c85272c58
 | |
| --- /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 877f7fa95466..6a176b3d43f9 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)
 | |
| -- 
 | |
| 2.19.1
 | |
| 
 |