aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/clk.txt4
-rw-r--r--Documentation/devicetree/bindings/arm/hs/hisilicon.txt42
-rw-r--r--Documentation/devicetree/bindings/clock/hi3716.txt121
-rw-r--r--Documentation/devicetree/bindings/dma/k3dma.txt46
-rw-r--r--Documentation/devicetree/bindings/gpio/gpio-pl061.txt33
-rw-r--r--Documentation/devicetree/bindings/mmc/hisilicon-dw-mshc.txt50
-rw-r--r--arch/arm/Kconfig2
-rw-r--r--arch/arm/Kconfig.debug15
-rw-r--r--arch/arm/Makefile1
-rw-r--r--arch/arm/boot/dts/Makefile2
-rw-r--r--arch/arm/boot/dts/hi3620.dtsi1606
-rw-r--r--arch/arm/boot/dts/hi3716-dkb.dts60
-rw-r--r--arch/arm/boot/dts/hi3716.dtsi280
-rw-r--r--arch/arm/boot/dts/hi4511.dts1478
-rw-r--r--arch/arm/configs/hs_defconfig1998
-rw-r--r--arch/arm/configs/multi_v7_defconfig2
-rw-r--r--arch/arm/include/debug/hisilicon.S35
-rw-r--r--arch/arm/kernel/setup.c7
-rw-r--r--arch/arm/mach-hs/Kconfig21
-rw-r--r--arch/arm/mach-hs/Makefile10
-rw-r--r--arch/arm/mach-hs/core.h28
-rw-r--r--arch/arm/mach-hs/hilpm-cpugodp.S1006
-rw-r--r--arch/arm/mach-hs/hipm.h183
-rw-r--r--arch/arm/mach-hs/hotplug.c154
-rw-r--r--arch/arm/mach-hs/hs-dt.c82
-rw-r--r--arch/arm/mach-hs/lowpmregs.c150
-rw-r--r--arch/arm/mach-hs/platsmp.c48
-rw-r--r--arch/arm/mach-hs/pm.c495
-rw-r--r--arch/arm/mach-hs/system.c65
-rw-r--r--arch/arm/mach-imx/clk.h3
-rw-r--r--drivers/clk/Kconfig1
-rw-r--r--drivers/clk/Makefile1
-rw-r--r--drivers/clk/clk-gate.c25
-rw-r--r--drivers/clk/clk-hi3xxx.c643
-rw-r--r--drivers/clk/clk-mux.c13
-rw-r--r--drivers/clk/clk.c458
-rw-r--r--drivers/clk/hisilicon/Kconfig7
-rw-r--r--drivers/clk/hisilicon/Makefile2
-rw-r--r--drivers/clk/hisilicon/clk-hi3620-dsi.c364
-rw-r--r--drivers/clk/hisilicon/clk-hi3716.c268
-rw-r--r--drivers/clk/hisilicon/clk-hi3xxx.c641
-rw-r--r--drivers/clk/mmp/clk-mmp2.c39
-rw-r--r--drivers/clk/mmp/clk-pxa168.c40
-rw-r--r--drivers/clk/mmp/clk-pxa910.c31
-rw-r--r--drivers/clk/mxs/clk.h4
-rw-r--r--drivers/clk/spear/spear1310_clock.c179
-rw-r--r--drivers/clk/spear/spear1340_clock.c97
-rw-r--r--drivers/clk/spear/spear3xx_clock.c57
-rw-r--r--drivers/clk/spear/spear6xx_clock.c35
-rw-r--r--drivers/clk/tegra/clk-tegra20.c6
-rw-r--r--drivers/clk/tegra/clk-tegra30.c33
-rw-r--r--drivers/dma/Kconfig9
-rw-r--r--drivers/dma/Makefile1
-rw-r--r--drivers/dma/amba-pl08x.c31
-rw-r--r--drivers/dma/dmaengine.c26
-rw-r--r--drivers/dma/k3dma.c849
-rw-r--r--drivers/gpio/gpio-pl061.c22
-rw-r--r--drivers/gpio/gpiolib.c8
-rw-r--r--drivers/i2c/busses/i2c-designware-platdrv.c14
-rw-r--r--drivers/input/misc/Kconfig9
-rw-r--r--drivers/input/misc/Makefile1
-rw-r--r--drivers/input/misc/hi6421_pwrkey.c153
-rw-r--r--drivers/input/touchscreen/Kconfig12
-rw-r--r--drivers/input/touchscreen/Makefile1
-rw-r--r--drivers/input/touchscreen/atmel_mXT224E.c1473
-rw-r--r--drivers/mfd/Kconfig14
-rw-r--r--drivers/mfd/Makefile2
-rw-r--r--drivers/mfd/hi6421-pmic-core.c310
-rw-r--r--drivers/mfd/r63306.c327
-rw-r--r--drivers/mmc/card/block.c32
-rw-r--r--drivers/mmc/core/bus.c14
-rw-r--r--drivers/mmc/core/core.c47
-rw-r--r--drivers/mmc/core/core.h3
-rw-r--r--drivers/mmc/core/debugfs.c8
-rw-r--r--drivers/mmc/core/mmc.c60
-rw-r--r--drivers/mmc/core/sd.c53
-rw-r--r--drivers/mmc/core/sdio.c16
-rw-r--r--drivers/mmc/host/Kconfig10
-rw-r--r--drivers/mmc/host/Makefile1
-rw-r--r--drivers/mmc/host/dw_mmc-exynos.c2
-rw-r--r--drivers/mmc/host/dw_mmc-hisilicon.c395
-rw-r--r--drivers/mmc/host/dw_mmc-pltfm.c2
-rw-r--r--drivers/mmc/host/dw_mmc.c70
-rw-r--r--drivers/regulator/Kconfig7
-rw-r--r--drivers/regulator/Makefile2
-rw-r--r--drivers/regulator/hi6421-regulator.c560
-rw-r--r--drivers/rtc/Kconfig11
-rw-r--r--drivers/rtc/Makefile1
-rw-r--r--drivers/rtc/rtc-hi6421.c259
-rw-r--r--drivers/rtc/rtc-pl031.c28
-rw-r--r--drivers/staging/android/ashmem.c24
-rw-r--r--drivers/video/Kconfig1
-rw-r--r--drivers/video/Makefile1
-rw-r--r--drivers/video/fbmon.c10
-rw-r--r--drivers/video/hisilicon/Kconfig11
-rw-r--r--drivers/video/hisilicon/Makefile2
-rw-r--r--drivers/video/hisilicon/hi3620_dsi.c626
-rw-r--r--drivers/video/hisilicon/hi3620_fb.c926
-rw-r--r--drivers/video/hisilicon/hi3620_fb.h208
-rw-r--r--include/linux/clk-private.h3
-rw-r--r--include/linux/clk-provider.h19
-rw-r--r--include/linux/dmaengine.h1
-rw-r--r--include/linux/mfd/hi6421-pmic.h99
-rw-r--r--include/linux/mfd/r63306.h45
-rw-r--r--include/linux/mmc/core.h3
-rw-r--r--include/linux/mmc/dw_mmc.h3
-rw-r--r--include/linux/mmc/host.h2
-rw-r--r--include/linux/nmi.h5
-rw-r--r--include/linux/platform_data/hi3620-dsi.h53
-rw-r--r--include/uapi/linux/fb.h5
-rw-r--r--kernel/watchdog.c123
-rw-r--r--lib/Kconfig.debug14
-rw-r--r--linaro/configs/android.conf1
113 files changed, 17406 insertions, 593 deletions
diff --git a/Documentation/clk.txt b/Documentation/clk.txt
index b9911c27f496..3110ba472e8a 100644
--- a/Documentation/clk.txt
+++ b/Documentation/clk.txt
@@ -70,6 +70,10 @@ the operations defined in clk.h:
unsigned long parent_rate);
long (*round_rate)(struct clk_hw *hw, unsigned long,
unsigned long *);
+ long (*determine_rate)(struct clk_hw *hw,
+ unsigned long rate,
+ unsigned long *best_parent_rate,
+ struct clk **best_parent_clk);
int (*set_parent)(struct clk_hw *hw, u8 index);
u8 (*get_parent)(struct clk_hw *hw);
int (*set_rate)(struct clk_hw *hw, unsigned long);
diff --git a/Documentation/devicetree/bindings/arm/hs/hisilicon.txt b/Documentation/devicetree/bindings/arm/hs/hisilicon.txt
new file mode 100644
index 000000000000..41ac783542e1
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/hs/hisilicon.txt
@@ -0,0 +1,42 @@
+Hisilicon Platforms Device Tree Bindings
+----------------------------------------------------
+
+Hi3716 Development Board
+Required root node properties:
+ - compatible = "hisilicon,hi3716-dkb";
+
+Hi4511 Board
+Required root node properties:
+ - compatible = "hisilicon,hi3620-hi4511";
+
+
+Hisilicon sctrl resiter description
+
+Required properties:
+- compatible : "hisilicon,sctrl"
+- reg : Address and size of sysctrl.
+- smp_reg : offset in sysctrl for notifying slave cpu booting
+ cpu 1, reg;
+ cpu 2, reg + 0x4;
+ cpu 3, reg + 0x8;
+ If reg value is not zero, cpun exit wfi and go
+- resume_reg : offset in sysctrl for notifying cpu0 when resume
+- reset_reg : offset in sysctrl for system reset
+
+Example:
+ hi3716:
+ sctrl@f8000000 {
+ compatible = "hisilicon,sctrl";
+ reg = <0xf8000000 0x1000>;
+ smp_reg = <0xc0>;
+ reboot_reg = <0x4>;
+ };
+
+ hi3620:
+ sctrl@fc802000 {
+ compatible = "hisilicon,sctrl";
+ reg = <0xfc802000 0x1000>;
+ smp_reg = <0x31c>;
+ resume_reg = <0x308>;
+ reboot_reg = <0x4>;
+ };
diff --git a/Documentation/devicetree/bindings/clock/hi3716.txt b/Documentation/devicetree/bindings/clock/hi3716.txt
new file mode 100644
index 000000000000..60af61e1a413
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/hi3716.txt
@@ -0,0 +1,121 @@
+Device Tree Clock bindings for hi3716
+
+This binding uses the common clock binding[1].
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Clock control register
+Required properties:
+- compatible : "hisilicon,clkbase"
+- reg : Address and size of clkbase.
+
+Device Clocks
+
+Device clocks are required to have one or both of the following sets of
+properties:
+
+
+Gated device clocks:
+
+Required properties:
+- compatible : "hisilicon,hi3716-clk-gate"
+- gate-reg : shall be the register offset from clkbase and enable bit, reset bit
+- clock-output-names : shall be reference name
+
+
+Mux device clocks:
+
+Required properties:
+- compatible : "hisilicon,hi3716-clk-mux"
+- mux-reg : shall be the register offset from clkbase and mux_shift mux_width
+- mux-table : shall be reg value to be choose clocks accordingly
+- clock-output-names : shall be reference name
+
+
+Fixed divisor device clocks:
+
+Required properties:
+- compatible : "hisilicon,hi3716-fixed-divider"
+- div-table : shall be divisor sequence
+- clock-output-names : shall be reference name according to divisor
+
+
+Fixed pll clocks:
+
+Required properties:
+- compatible : "hisilicon,hi3716-fixed-pll"
+- clock-frequency : shall be output clock frequence sequence
+- clock-output-names : shall be reference name according to clock-frequnce
+
+For example:
+ clkbase@f8a22000 {
+ compatible = "hisilicon,clkbase";
+ reg = <0xf8a22000 0x1000>;
+ };
+
+ osc24m: osc {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <24000000>;
+ clock-output-names = "osc24mhz";
+ };
+
+ bpll: bpll {
+ compatible = "hisilicon,hi3716-fixed-pll";
+ #clock-cells = <1>;
+ clocks = <&osc24m>;
+ clock-frequency = <1200000000>,
+ <600000000>,
+ <300000000>,
+ <200000000>,
+ <150000000>;
+ clock-output-names = "bpll_fout0",
+ "bpll_fout1",
+ "bpll_fout2",
+ "bpll_fout3",
+ "bpll_fout4";
+ };
+
+ bpll_fout0_div: bpll_fout0_div {/* 1200Mhz */
+ compatible = "hisilicon,hi3716-fixed-divider";
+ #clock-cells = <1>;
+ clocks = <&bpll 0>;
+ div-table = <3 14 25 50>;
+ clock-output-names = "fout0_400m", "fout0_86m",
+ "fout0_48m", "fout0_24m";
+ };
+
+ bpll_fout3_div: bpll_fout3_div {
+ compatible = "hisilicon,hi3716-fixed-divider";
+ #clock-cells = <1>;
+ clocks = <&bpll 3>;
+ div-table = <2 4 5 8>;
+ clock-output-names = "fout3_100m", "fout3_50m",
+ "fout3_40m", "fout3_25m";
+ };
+
+ clk_sfc_mux: clk_sfc_mux {
+ compatible = "hisilicon,hi3716-clk-mux";
+ #clock-cells = <0>;
+ /* clks: 24M 75M 100M 150M 200M */
+ clocks = <&osc24m>, <&bpll_fout2_div>,
+ <&bpll_fout3_div 0>, <&bpll 4>, <&bpll 3>;
+
+ /* offset mux_shift mux_width */
+ mux-reg = <0x5c 8 3>;
+ /* mux reg value to choose clks */
+ mux-table = <0 7 6 4 5>;
+
+ clock-output-names = "sfc_mux";
+ };
+
+ clk_sfc: clk_sfc {
+ compatible = "hisilicon,hi3716-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&clk_sfc_mux>;
+
+ /* offset, enable, reset */
+ gate-reg = <0x5c 0 4>;
+
+ clock-output-names = "sfc";
+ };
diff --git a/Documentation/devicetree/bindings/dma/k3dma.txt b/Documentation/devicetree/bindings/dma/k3dma.txt
new file mode 100644
index 000000000000..23f8d712c3ce
--- /dev/null
+++ b/Documentation/devicetree/bindings/dma/k3dma.txt
@@ -0,0 +1,46 @@
+* Hisilicon K3 DMA controller
+
+See dma.txt first
+
+Required properties:
+- compatible: Should be "hisilicon,k3-dma-1.0"
+- reg: Should contain DMA registers location and length.
+- interrupts: Should contain one interrupt shared by all channel
+- #dma-cells: see dma.txt, should be 1, para number
+- dma-channels: physical channels supported
+- dma-requests: virtual channels supported, each virtual channel
+ have specific request line
+- clocks: clock required
+
+Example:
+
+Controller:
+ dma0: dma@fcd02000 {
+ compatible = "hisilicon,k3-dma-1.0";
+ reg = <0xfcd02000 0x1000>;
+ #dma-cells = <1>;
+ dma-channels = <16>;
+ dma-requests = <27>;
+ interrupts = <0 12 4>;
+ clocks = <&pclk>;
+ status = "disable";
+ };
+
+Client:
+Use specific request line passing from dmax
+For example, i2c0 read channel request line is 18, while write channel use 19
+
+ i2c0: i2c@fcb08000 {
+ compatible = "snps,designware-i2c";
+ dmas = <&dma0 18 /* read channel */
+ &dma0 19>; /* write channel */
+ dma-names = "rx", "tx";
+ };
+
+ i2c1: i2c@fcb09000 {
+ compatible = "snps,designware-i2c";
+ dmas = <&dma0 20 /* read channel */
+ &dma0 21>; /* write channel */
+ dma-names = "rx", "tx";
+ };
+
diff --git a/Documentation/devicetree/bindings/gpio/gpio-pl061.txt b/Documentation/devicetree/bindings/gpio/gpio-pl061.txt
new file mode 100644
index 000000000000..687206727bd3
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/gpio-pl061.txt
@@ -0,0 +1,33 @@
+PL061 GPIO controller bindings
+
+Required properties:
+- compatible:
+ - "arm,pl061", "arm,primecell".
+- #gpio-cells : Should be two.
+ - first cell is the gpio pin number
+ - second cell is used to specify the gpio polarity:
+ 0 = active high
+ 1 = active low
+- gpio-controller : Marks the device node as a GPIO controller.
+- interrupt-controller : Marks the device node as an interrupt controller.
+- #interrupt-cells : Should be two.
+ - first cell is the hw irq number
+ - second cell is used to specify the interrupt type:
+ 0 = default, unspecified type
+ 1 = rising edge triggered
+ 2 = falling edge triggered
+ 4 = high level triggered
+ 8 = low level triggered
+- linux,gpio-base : Should be the global GPIO number.
+
+Example:
+ gpio0: gpio@fc806000 {
+ compatible = "arm,pl061", "arm,primecell";
+ reg = <0xfc806000 0x1000>;
+ interrupts = <0 64 0x4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ linux,gpio-base = <0>;
+ };
diff --git a/Documentation/devicetree/bindings/mmc/hisilicon-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/hisilicon-dw-mshc.txt
new file mode 100644
index 000000000000..960eb32e5988
--- /dev/null
+++ b/Documentation/devicetree/bindings/mmc/hisilicon-dw-mshc.txt
@@ -0,0 +1,50 @@
+* Hisilicon specific extensions to the Synopsis Designware Mobile
+ Storage Host Controller
+
+Read synopsis-dw-mshc.txt for more details
+The Synopsis designware mobile storage host controller is used to interface
+a SoC with storage medium such as eMMC or SD/MMC cards. This file documents
+differences between the core Synopsis dw mshc controller properties described
+by synopsis-dw-mshc.txt and the properties used by the Hisilicon specific
+extensions to the Synopsis Designware Mobile Storage Host Controller.
+
+Required Properties:
+
+* compatible: should be
+ - "hisilicon,hi4511-dw-mshc": for controllers with hi4511
+ specific extentions.
+ - "hisilicon,hi3620-dw-mshc": for controllers with hi3620
+ specific extentions.
+
+Required properties for a slot:
+
+* vmmc-supply is vmmc used in dwmmc
+* fifo-depth should be provided if register can not provide correct value
+
+Example:
+
+ The MSHC controller node can be split into two portions, SoC specific and
+ board specific portions as listed below.
+
+ dwmmc_0: dwmmc0@fcd03000 {
+ compatible = "hisilicon,hi4511-dw-mshc";
+ reg = <0xfcd03000 0x1000>;
+ interrupts = <0 16 4>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clocks = <&clk_sd>, <&clk_ddrc_per>;
+ clock-names = "ciu", "biu";
+ };
+ dwmmc0@fcd03000 {
+ num-slots = <1>;
+ vmmc-supply = <&ldo12>;
+ fifo-depth = <0x100>;
+ supports-highspeed;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sd_pmx_pins &sd_cfg_func1 &sd_cfg_func2>;
+ slot@0 {
+ reg = <0>;
+ bus-width = <4>;
+ hisilicon,cd-pinmux-gpio = <&gpio10 3 0>;
+ };
+ };
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 3d2e60807861..ec94c57ef942 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -938,6 +938,8 @@ source "arch/arm/mach-gemini/Kconfig"
source "arch/arm/mach-highbank/Kconfig"
+source "arch/arm/mach-hs/Kconfig"
+
source "arch/arm/mach-integrator/Kconfig"
source "arch/arm/mach-iop32x/Kconfig"
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 21cc8a765988..1d61af02b604 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -272,6 +272,20 @@ choice
Say Y here if you want kernel low-level debugging support
on i.MX6Q/DL.
+ config DEBUG_HI3620_UART0
+ bool "Hisilicon HI3620 Debug UART0"
+ depends on ARCH_HS
+ help
+ Say Y here if you want kernel low-level debugging support
+ on HI3620 UART0.
+
+ config DEBUG_HI3716_UART0
+ bool "Hisilicon HI3716 Debug UART0"
+ depends on ARCH_HS
+ help
+ Say Y here if you want kernel low-level debugging support
+ on HI3716 UART0.
+
config DEBUG_MMP_UART2
bool "Kernel low-level debugging message via MMP UART2"
depends on ARCH_MMP
@@ -644,6 +658,7 @@ config DEBUG_LL_INCLUDE
default "debug/cns3xxx.S" if DEBUG_CNS3XXX
default "debug/exynos.S" if DEBUG_EXYNOS_UART
default "debug/highbank.S" if DEBUG_HIGHBANK_UART
+ default "debug/hisilicon.S" if DEBUG_HI3620_UART0 || DEBUG_HI3716_UART0
default "debug/icedcc.S" if DEBUG_ICEDCC
default "debug/imx.S" if DEBUG_IMX1_UART || \
DEBUG_IMX25_UART || \
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 883e4bec807f..ee69c43c61af 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -148,6 +148,7 @@ machine-$(CONFIG_ARCH_EBSA110) += ebsa110
machine-$(CONFIG_ARCH_EP93XX) += ep93xx
machine-$(CONFIG_ARCH_GEMINI) += gemini
machine-$(CONFIG_ARCH_HIGHBANK) += highbank
+machine-$(CONFIG_ARCH_HS) += hs
machine-$(CONFIG_ARCH_INTEGRATOR) += integrator
machine-$(CONFIG_ARCH_IOP13XX) += iop13xx
machine-$(CONFIG_ARCH_IOP32X) += iop32x
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 00baf9f5766a..937ba39020cf 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -60,6 +60,8 @@ dtb-$(CONFIG_ARCH_EXYNOS) += exynos4210-origen.dtb \
exynos5440-ssdk5440.dtb
dtb-$(CONFIG_ARCH_HIGHBANK) += highbank.dtb \
ecx-2000.dtb
+dtb-$(CONFIG_ARCH_HS) += hi4511.dtb \
+ hi3716-dkb.dtb
dtb-$(CONFIG_ARCH_INTEGRATOR) += integratorap.dtb \
integratorcp.dtb
dtb-$(CONFIG_ARCH_LPC32XX) += ea3250.dtb phy3250.dtb
diff --git a/arch/arm/boot/dts/hi3620.dtsi b/arch/arm/boot/dts/hi3620.dtsi
new file mode 100644
index 000000000000..7ba98c698ca0
--- /dev/null
+++ b/arch/arm/boot/dts/hi3620.dtsi
@@ -0,0 +1,1606 @@
+/*
+ * Hisilicon Ltd. Hi3620 SoC
+ *
+ * Copyright (C) 2012-2013 Linaro Ltd.
+ * Author: Haojian Zhuang <haojian.zhuang@linaro.org>
+ *
+ * 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
+ * publishhed by the Free Software Foundation.
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+ aliases {
+ serial0 = &uart0;
+ serial1 = &uart1;
+ mshc0 = &dwmmc_0;
+ mshc1 = &dwmmc_1;
+ mshc2 = &dwmmc_2;
+ mshc3 = &dwmmc_3;
+ };
+
+ osc32k: osc@0 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <32768>;
+ clock-output-names = "osc32khz";
+ };
+ osc26m: osc@1 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <26000000>;
+ clock-output-names = "osc26mhz";
+ };
+ pclk: clk@0 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <26000000>;
+ clock-output-names = "apb_pclk";
+ };
+ pll_arm0: clk@1 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <1600000000>;
+ clock-output-names = "armpll0";
+ };
+ pll_arm1: clk@2 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <1600000000>;
+ clock-output-names = "armpll1";
+ };
+ pll_peri: clk@3 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <1440000000>;
+ clock-output-names = "armpll2";
+ };
+ pll_usb: clk@4 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <1440000000>;
+ clock-output-names = "armpll3";
+ };
+ pll_hdmi: clk@5 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <1188000000>;
+ clock-output-names = "armpll4";
+ };
+ pll_gpu: clk@6 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <1300000000>;
+ clock-output-names = "armpll5";
+ };
+
+
+ amba {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "arm,amba-bus";
+ interrupt-parent = <&intc>;
+ ranges;
+
+ pmctrl: pmctrl@fca08000 {
+ compatible = "hisilicon,pmctrl";
+ reg = <0xfca08000 0x1000>;
+ };
+
+ pctrl: pctrl@fca09000 {
+ compatible = "hisilicon,pctrl";
+ reg = <0xfca09000 0x1000>;
+ };
+
+ secram: secram@f8000000 {
+ compatible = "hisilicon,secram";
+ reg = <0xf8000000 0x14000>;
+ };
+
+ ddrcfg: ddrcfg@fcd00000 {
+ compatible = "hisilicon,ddrcfg";
+ reg = <0xfcd00000 0x2000>;
+ };
+
+
+ sctrl: sctrl@fc802000 {
+ compatible = "hisilicon,sctrl";
+ reg = <0xfc802000 0x1000>;
+ smp_reg = <0x31c>;
+ resume_reg = <0x308>;
+ reboot_reg = <0x4>;
+
+ refclk_uart0: refclk@0 {
+ compatible = "hisilicon,hi3620-clk-mux";
+ #clock-cells = <0>;
+ clocks = <&osc26m &pclk>;
+ hiword;
+ clock-output-names = "rclk_uart0";
+ /* reg_offset, enable_bits */
+ hisilicon,clkmux-reg = <0x100 0x80>;
+ hisilicon,clkmux-table = <0 1>;
+ };
+ refclk_uart1: refclk@1 {
+ compatible = "hisilicon,hi3620-clk-mux";
+ #clock-cells = <0>;
+ clocks = <&osc26m &pclk>;
+ hiword;
+ clock-output-names = "rclk_uart1";
+ hisilicon,clkmux-reg = <0x100 0x100>;
+ hisilicon,clkmux-table = <0 1>;
+ };
+ refclk_uart2: refclk@2 {
+ compatible = "hisilicon,hi3620-clk-mux";
+ #clock-cells = <0>;
+ clocks = <&osc26m &pclk>;
+ hiword;
+ clock-output-names = "rclk_uart2";
+ hisilicon,clkmux-reg = <0x100 0x200>;
+ hisilicon,clkmux-table = <0 1>;
+ };
+ refclk_uart3: refclk@3 {
+ compatible = "hisilicon,hi3620-clk-mux";
+ #clock-cells = <0>;
+ clocks = <&osc26m &pclk>;
+ hiword;
+ clock-output-names = "rclk_uart3";
+ hisilicon,clkmux-reg = <0x100 0x400>;
+ hisilicon,clkmux-table = <0 1>;
+ };
+ refclk_uart4: refclk@4 {
+ compatible = "hisilicon,hi3620-clk-mux";
+ #clock-cells = <0>;
+ clocks = <&osc26m &pclk>;
+ hiword;
+ clock-output-names = "rclk_uart4";
+ hisilicon,clkmux-reg = <0x100 0x800>;
+ hisilicon,clkmux-table = <0 1>;
+ };
+
+ refclk_hsic: hsic {
+ compatible = "hisilicon,hi3620-clk-mux";
+ #clock-cells = <0>;
+ clocks = <&pll_usb &pll_peri>;
+ hiword;
+ clock-output-names = "rclk_hsic";
+ hisilicon,clkmux-reg = <0x130 0x4>;
+ hisilicon,clkmux-table = <0 1>;
+ };
+
+ clk_osc480m: clk_osc480m {
+ compatible = "hisilicon,hi3620-clk-div";
+ #clock-cells = <0>;
+ clocks = <&refclk_hsic>;
+ clock-output-names = "clk_osc480m";
+ hisilicon,clkdiv-table = <4 1>;
+ /* divider register offset, mask */
+ hisilicon,clkdiv = <0x130 0xf>;
+ };
+ refclk_cfgaxi: refclk@5 {
+ compatible = "hisilicon,clk-fixed-factor";
+ #clock-cells = <0>;
+ clocks = <&pll_peri>;
+ clock-output-names = "rclk_cfgaxi";
+ /*mult, div*/
+ hisilicon,fixed-factor = <1 30>;
+ };
+ refclk_spi0: refclk@6 {
+ compatible = "hisilicon,hi3620-clk-mux";
+ #clock-cells = <0>;
+ clocks = <&osc26m &refclk_cfgaxi>;
+ hiword;
+ clock-output-names = "rclk_spi0";
+ hisilicon,clkmux-reg = <0x100 0x1000>;
+ hisilicon,clkmux-table = <0 1>;
+ };
+ refclk_spi1: refclk@7 {
+ compatible = "hisilicon,hi3620-clk-mux";
+ #clock-cells = <0>;
+ clocks = <&osc26m &refclk_cfgaxi>;
+ hiword;
+ clock-output-names = "rclk_spi1";
+ hisilicon,clkmux-reg = <0x100 0x2000>;
+ hisilicon,clkmux-table = <0 1>;
+ };
+ refclk_spi2: refclk@8 {
+ compatible = "hisilicon,hi3620-clk-mux";
+ #clock-cells = <0>;
+ clocks = <&osc26m &refclk_cfgaxi>;
+ hiword;
+ clock-output-names = "rclk_spi2";
+ hisilicon,clkmux-reg = <0x100 0x4000>;
+ hisilicon,clkmux-table = <0 1>;
+ };
+ refclk_tcxo: refclk@11 {
+ compatible = "hisilicon,clk-fixed-factor";
+ #clock-cells = <0>;
+ clocks = <&osc26m>;
+ clock-output-names = "rclk_tcxo";
+ hisilicon,fixed-factor = <1 4>;
+ };
+ timer0_mux: timer0_mux {
+ compatible = "hisilicon,hi3620-clk-mux";
+ #clock-cells = <0>;
+ clocks = <&osc32k &timerclk01>;
+ clock-output-names = "timer0_mux";
+ hisilicon,clkmux-reg = <0 0x18000>;
+ hisilicon,clkmux-table = <0 1>;
+ };
+ timer1_mux: timer1_mux {
+ compatible = "hisilicon,hi3620-clk-mux";
+ #clock-cells = <0>;
+ clocks = <&osc32k &timerclk01>;
+ clock-output-names = "timer1_mux";
+ hisilicon,clkmux-reg = <0 0x60000>;
+ hisilicon,clkmux-table = <0 1>;
+ };
+ timer2_mux: timer2_mux {
+ compatible = "hisilicon,hi3620-clk-mux";
+ #clock-cells = <0>;
+ clocks = <&osc32k &timerclk23>;
+ clock-output-names = "timer2_mux";
+ hisilicon,clkmux-reg = <0 0x180000>;
+ hisilicon,clkmux-table = <0 1>;
+ };
+ timer3_mux: timer3_mux {
+ compatible = "hisilicon,hi3620-clk-mux";
+ #clock-cells = <0>;
+ clocks = <&osc32k &timerclk23>;
+ clock-output-names = "timer3_mux";
+ hisilicon,clkmux-reg = <0 0x600000>;
+ hisilicon,clkmux-table = <0 1>;
+ };
+ timer4_mux: timer4_mux {
+ compatible = "hisilicon,hi3620-clk-mux";
+ #clock-cells = <0>;
+ clocks = <&osc32k &timerclk45>;
+ clock-output-names = "timer4_mux";
+ hisilicon,clkmux-reg = <0x18 0x3>;
+ hisilicon,clkmux-table = <0 1>;
+ };
+ timer5_mux: timer5_mux {
+ compatible = "hisilicon,hi3620-clk-mux";
+ #clock-cells = <0>;
+ clocks = <&osc32k &timerclk45>;
+ clock-output-names = "timer5_mux";
+ hisilicon,clkmux-reg = <0x18 0xc>;
+ hisilicon,clkmux-table = <0 1>;
+ };
+ timer6_mux: timer6_mux {
+ compatible = "hisilicon,hi3620-clk-mux";
+ #clock-cells = <0>;
+ clocks = <&osc32k &timerclk67>;
+ clock-output-names = "timer6_mux";
+ hisilicon,clkmux-reg = <0x18 0x30>;
+ hisilicon,clkmux-table = <0 1>;
+ };
+ timer7_mux: timer7_mux {
+ compatible = "hisilicon,hi3620-clk-mux";
+ #clock-cells = <0>;
+ clocks = <&osc32k &timerclk67>;
+ clock-output-names = "timer7_mux";
+ hisilicon,clkmux-reg = <0x18 0xc0>;
+ hisilicon,clkmux-table = <0 1>;
+ };
+ refclk_shareAXI: refclk@22 {
+ compatible = "hisilicon,hi3620-clk-mux";
+ #clock-cells = <0>;
+ clocks = <&pll_usb &pll_peri>;
+ hiword;
+ clock-output-names = "rclk_shareAXI";
+ hisilicon,clkmux-reg = <0x24 0x8000>;
+ hisilicon,clkmux-table = <0 1>;
+ };
+ refclk_mmc1: refclk@23 {
+ compatible = "hisilicon,hi3620-clk-mux";
+ #clock-cells = <0>;
+ clocks = <&pll_peri &pll_usb>;
+ hiword;
+ clock-output-names = "rclk_mmc1";
+ hisilicon,clkmux-reg = <0x108 0x200>;
+ hisilicon,clkmux-table = <0 1>;
+ };
+ refclk_mmc2: refclk@24 {
+ compatible = "hisilicon,hi3620-clk-mux";
+ #clock-cells = <0>;
+ clocks = <&pll_peri &pll_usb>;
+ hiword;
+ clock-output-names = "rclk_mmc2";
+ hisilicon,clkmux-reg = <0x140 0x10>;
+ hisilicon,clkmux-table = <0 1>;
+ };
+ refclk_mmc3: refclk@25 {
+ compatible = "hisilicon,hi3620-clk-mux";
+ #clock-cells = <0>;
+ clocks = <&pll_peri &pll_usb>;
+ hiword;
+ clock-output-names = "rclk_mmc3";
+ hisilicon,clkmux-reg = <0x140 0x200>;
+ hisilicon,clkmux-table = <0 1>;
+ };
+ refclk_sd: refclk@26 {
+ compatible = "hisilicon,hi3620-clk-mux";
+ #clock-cells = <0>;
+ clocks = <&pll_peri &pll_usb>;
+ hiword;
+ clock-output-names = "rclk_sd";
+ hisilicon,clkmux-reg = <0x108 0x10>;
+ hisilicon,clkmux-table = <0 1>;
+ };
+ refclk_mmc1_parent: refclk@27 {
+ compatible = "hisilicon,hi3620-clk-mux";
+ #clock-cells = <0>;
+ hiword;
+ clocks = <&osc26m &div_mmc1>;
+ clock-output-names = "rclk_mmc1_parent";
+ hisilicon,clkmux-reg = <0x108 0x400>;
+ hisilicon,clkmux-table = <0 1>;
+ };
+ refclk_venc: refclk@28 {
+ compatible = "hisilicon,hi3620-clk-mux";
+ #clock-cells = <0>;
+ hiword;
+ clocks = <&pll_peri &pll_usb>;
+ clock-output-names = "rclk_venc";
+ hisilicon,clkmux-reg = <0x10c 0x800>;
+ hisilicon,clkmux-table = <0 1>;
+ };
+ refclk_g2d: refclk@29 {
+ compatible = "hisilicon,hi3620-clk-mux";
+ #clock-cells = <0>;
+ hiword;
+ clocks = <&pll_peri &pll_usb>;
+ clock-output-names = "rclk_g2d";
+ hisilicon,clkmux-reg = <0x10c 0x20>;
+ hisilicon,clkmux-table = <0 1>;
+ };
+ refclk_vdec: refclk@30 {
+ compatible = "hisilicon,hi3620-clk-mux";
+ #clock-cells = <0>;
+ hiword;
+ clocks = <&pll_peri &pll_usb>;
+ clock-output-names = "rclk_vdec";
+ hisilicon,clkmux-reg = <0x110 0x20>;
+ hisilicon,clkmux-table = <0 1>;
+ };
+ refclk_vpp: refclk@31 {
+ compatible = "hisilicon,hi3620-clk-mux";
+ #clock-cells = <0>;
+ hiword;
+ clocks = <&pll_peri &pll_usb>;
+ clock-output-names = "rclk_vpp";
+ hisilicon,clkmux-reg = <0x110 0x800>;
+ hisilicon,clkmux-table = <0 1>;
+ };
+ refclk_ldi0: refclk@32 {
+ compatible = "hisilicon,hi3620-clk-mux";
+ #clock-cells = <0>;
+ hiword;
+ clocks = <&pll_peri &pll_hdmi &pll_usb>;
+ clock-output-names = "rclk_ldi0";
+ hisilicon,clkmux-reg = <0x114 0x6000>;
+ hisilicon,clkmux-table = <0 1 2>;
+ };
+ refclk_ldi1: refclk@33 {
+ compatible = "hisilicon,hi3620-clk-mux";
+ #clock-cells = <0>;
+ hiword;
+ clocks = <&pll_peri &pll_hdmi &pll_usb>;
+ clock-output-names = "rclk_ldi1";
+ hisilicon,clkmux-reg = <0x118 0xc000>;
+ hisilicon,clkmux-table = <0 1 2>;
+ };
+ clk_osc480mdiv40: osc480mdiv40 {
+ compatible = "hisilicon,clk-fixed-factor";
+ #clock-cells = <0>;
+ clocks = <&clk_osc480m>;
+ /*mult, div*/
+ hisilicon,fixed-factor = <1 40>;
+ clock-output-names = "clk_osc480mdiv40";
+ };
+ clk_usbpicophy: usbpicophy {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&clk_osc480mdiv40>;
+ clock-output-names = "clk_usbpicophy";
+ hisilicon,hi3620-clkreset = <0x8c 0x1000000>;
+ hisilicon,hi3620-clkgate = <0x30 0x1000000>;
+ };
+ clk_usb2dvc: usb2dvc {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&refclk_cfgaxi>;
+ clock-output-names = "clk_usb2dvc";
+ hisilicon,hi3620-clkreset = <0xa4 0x20000>;
+ hisilicon,hi3620-clkgate = <0x50 0x20000>;
+ };
+ uartclk0: clkgate@0 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&refclk_uart0>;
+ clock-output-names = "uartclk0";
+ hisilicon,hi3620-clkreset = <0x98 0x10000>;
+ hisilicon,hi3620-clkgate = <0x40 0x10000>;
+ };
+ uartclk1: clkgate@1 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&refclk_uart1>;
+ clock-output-names = "uartclk1";
+ hisilicon,hi3620-clkreset = <0x98 0x20000>;
+ hisilicon,hi3620-clkgate = <0x40 0x20000>;
+ };
+ uartclk2: clkgate@2 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&refclk_uart2>;
+ clock-output-names = "uartclk2";
+ hisilicon,hi3620-clkreset = <0x98 0x40000>;
+ hisilicon,hi3620-clkgate = <0x40 0x40000>;
+ };
+ uartclk3: clkgate@3 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&refclk_uart3>;
+ clock-output-names = "uartclk3";
+ hisilicon,hi3620-clkreset = <0x98 0x80000>;
+ hisilicon,hi3620-clkgate = <0x40 0x80000>;
+ };
+ uartclk4: clkgate@4 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&refclk_uart4>;
+ clock-output-names = "uartclk4";
+ hisilicon,hi3620-clkreset = <0x98 0x100000>;
+ hisilicon,hi3620-clkgate = <0x40 0x100000>;
+ };
+ gpioclk0: clkgate@5 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&pclk>;
+ clock-output-names = "gpioclk0";
+ hisilicon,hi3620-clkreset = <0x80 0x100>;
+ hisilicon,hi3620-clkgate = <0x20 0x100>;
+ };
+ gpioclk1: clkgate@6 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&pclk>;
+ clock-output-names = "gpioclk1";
+ hisilicon,hi3620-clkreset = <0x80 0x200>;
+ hisilicon,hi3620-clkgate = <0x20 0x200>;
+ };
+ gpioclk2: clkgate@7 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&pclk>;
+ clock-output-names = "gpioclk2";
+ hisilicon,hi3620-clkreset = <0x80 0x400>;
+ hisilicon,hi3620-clkgate = <0x20 0x400>;
+ };
+ gpioclk3: clkgate@8 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&pclk>;
+ clock-output-names = "gpioclk3";
+ hisilicon,hi3620-clkreset = <0x80 0x800>;
+ hisilicon,hi3620-clkgate = <0x20 0x800>;
+ };
+ gpioclk4: clkgate@9 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&pclk>;
+ clock-output-names = "gpioclk4";
+ hisilicon,hi3620-clkreset = <0x80 0x1000>;
+ hisilicon,hi3620-clkgate = <0x20 0x1000>;
+ };
+ gpioclk5: clkgate@10 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&pclk>;
+ clock-output-names = "gpioclk5";
+ hisilicon,hi3620-clkreset = <0x80 0x2000>;
+ hisilicon,hi3620-clkgate = <0x20 0x2000>;
+ };
+ gpioclk6: clkgate@11 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&pclk>;
+ clock-output-names = "gpioclk6";
+ hisilicon,hi3620-clkreset = <0x80 0x4000>;
+ hisilicon,hi3620-clkgate = <0x20 0x4000>;
+ };
+ gpioclk7: clkgate@12 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&pclk>;
+ clock-output-names = "gpioclk7";
+ hisilicon,hi3620-clkreset = <0x80 0x8000>;
+ hisilicon,hi3620-clkgate = <0x20 0x8000>;
+ };
+ gpioclk8: clkgate@13 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&pclk>;
+ clock-output-names = "gpioclk8";
+ hisilicon,hi3620-clkreset = <0x80 0x10000>;
+ hisilicon,hi3620-clkgate = <0x20 0x10000>;
+ };
+ gpioclk9: clkgate@14 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&pclk>;
+ clock-output-names = "gpioclk9";
+ hisilicon,hi3620-clkreset = <0x80 0x20000>;
+ hisilicon,hi3620-clkgate = <0x20 0x20000>;
+ };
+ gpioclk10: clkgate@15 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&pclk>;
+ clock-output-names = "gpioclk10";
+ hisilicon,hi3620-clkreset = <0x80 0x40000>;
+ hisilicon,hi3620-clkgate = <0x20 0x40000>;
+ };
+ gpioclk11: clkgate@16 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&pclk>;
+ clock-output-names = "gpioclk11";
+ hisilicon,hi3620-clkreset = <0x80 0x80000>;
+ hisilicon,hi3620-clkgate = <0x20 0x80000>;
+ };
+ gpioclk12: clkgate@17 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&pclk>;
+ clock-output-names = "gpioclk12";
+ hisilicon,hi3620-clkreset = <0x80 0x100000>;
+ hisilicon,hi3620-clkgate = <0x20 0x100000>;
+ };
+ gpioclk13: clkgate@18 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&pclk>;
+ clock-output-names = "gpioclk13";
+ hisilicon,hi3620-clkreset = <0x80 0x200000>;
+ hisilicon,hi3620-clkgate = <0x20 0x200000>;
+ };
+ gpioclk14: clkgate@19 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&pclk>;
+ clock-output-names = "gpioclk14";
+ hisilicon,hi3620-clkreset = <0x80 0x400000>;
+ hisilicon,hi3620-clkgate = <0x20 0x400000>;
+ };
+ gpioclk15: clkgate@20 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&pclk>;
+ clock-output-names = "gpioclk15";
+ hisilicon,hi3620-clkreset = <0x80 0x800000>;
+ hisilicon,hi3620-clkgate = <0x20 0x800000>;
+ };
+ gpioclk16: clkgate@21 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&pclk>;
+ clock-output-names = "gpioclk16";
+ hisilicon,hi3620-clkreset = <0x80 0x1000000>;
+ hisilicon,hi3620-clkgate = <0x20 0x1000000>;
+ };
+ gpioclk17: clkgate@22 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&pclk>;
+ clock-output-names = "gpioclk17";
+ hisilicon,hi3620-clkreset = <0x80 0x2000000>;
+ hisilicon,hi3620-clkgate = <0x20 0x2000000>;
+ };
+ gpioclk18: clkgate@23 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&pclk>;
+ clock-output-names = "gpioclk18";
+ hisilicon,hi3620-clkreset = <0x80 0x4000000>;
+ hisilicon,hi3620-clkgate = <0x20 0x4000000>;
+ };
+ gpioclk19: clkgate@24 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&pclk>;
+ clock-output-names = "gpioclk19";
+ hisilicon,hi3620-clkreset = <0x80 0x8000000>;
+ hisilicon,hi3620-clkgate = <0x20 0x8000000>;
+ };
+ gpioclk20: clkgate@25 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&pclk>;
+ clock-output-names = "gpioclk20";
+ hisilicon,hi3620-clkreset = <0x80 0x10000000>;
+ hisilicon,hi3620-clkgate = <0x20 0x10000000>;
+ };
+ gpioclk21: clkgate@26 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&pclk>;
+ clock-output-names = "gpioclk21";
+ hisilicon,hi3620-clkreset = <0x80 0x20000000>;
+ hisilicon,hi3620-clkgate = <0x20 0x20000000>;
+ };
+ spiclk0: clkgate@27 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&refclk_spi0>;
+ clock-output-names = "spiclk0";
+ hisilicon,hi3620-clkreset = <0x98 0x200000>;
+ hisilicon,hi3620-clkgate = <0x40 0x200000>;
+ };
+ spiclk1: clkgate@28 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&refclk_spi1>;
+ clock-output-names = "spiclk1";
+ hisilicon,hi3620-clkreset = <0x98 0x400000>;
+ hisilicon,hi3620-clkgate = <0x40 0x400000>;
+ };
+ spiclk2: clkgate@29 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&refclk_spi2>;
+ clock-output-names = "spiclk2";
+ hisilicon,hi3620-clkreset = <0x98 0x800000>;
+ hisilicon,hi3620-clkgate = <0x40 0x800000>;
+ };
+ pwm0_mux: pwm0_mux {
+ compatible = "hisilicon,hi3620-clk-mux";
+ #clock-cells = <0>;
+ clocks = <&osc32k &pwm_divider>;
+ hiword;
+ clock-output-names = "pwm0_mux";
+ hisilicon,clkmux-reg = <0x104 0x400>;
+ hisilicon,clkmux-table = <0 1>;
+ };
+ pwm1_mux: pwm1_mux {
+ compatible = "hisilicon,hi3620-clk-mux";
+ #clock-cells = <0>;
+ clocks = <&osc32k &pwm_divider>;
+ hiword;
+ clock-output-names = "pwm1_mux";
+ hisilicon,clkmux-reg = <0x104 0x800>;
+ hisilicon,clkmux-table = <0 1>;
+ };
+ pwmclk0: clkgate@30 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&pwm0_mux>;
+ clock-output-names = "pwmclk0";
+ hisilicon,hi3620-clkreset = <0x98 0x80>;
+ hisilicon,hi3620-clkgate = <0x40 0x80>;
+ };
+ pwmclk1: clkgate@31 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&pwm1_mux>;
+ clock-output-names = "pwmclk1";
+ hisilicon,hi3620-clkreset = <0x98 0x100>;
+ hisilicon,hi3620-clkgate = <0x40 0x100>;
+ };
+ timerclk01: clkgate@32 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&refclk_tcxo>;
+ clock-output-names = "timerclk01";
+ hisilicon,hi3620-clkreset = <0x80 0x1>;
+ hisilicon,hi3620-clkgate = <0x20 0x3>;
+ };
+ timerclk23: clkgate@33 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&refclk_tcxo>;
+ clock-output-names = "timerclk23";
+ hisilicon,hi3620-clkreset = <0x80 0x2>;
+ hisilicon,hi3620-clkgate = <0x20 0xc>;
+ };
+ timerclk45: clkgate@34 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&refclk_tcxo>;
+ clock-output-names = "timerclk45";
+ hisilicon,hi3620-clkreset = <0x98 0x8>;
+ hisilicon,hi3620-clkgate = <0x40 0x8>;
+ };
+ timerclk67: clkgate@35 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&refclk_tcxo>;
+ clock-output-names = "timerclk67";
+ hisilicon,hi3620-clkreset = <0x98 0x10>;
+ hisilicon,hi3620-clkgate = <0x40 0x10>;
+ };
+ timerclk89: clkgate@36 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&refclk_tcxo>;
+ clock-output-names = "timerclk89";
+ hisilicon,hi3620-clkreset = <0x98 0x20>;
+ hisilicon,hi3620-clkgate = <0x40 0x20>;
+ };
+ rtcclk: clkgate@47 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&pclk>;
+ clock-output-names = "clk_rtc";
+ hisilicon,hi3620-clkgate = <0x20 0x20>;
+ };
+ i2cclk0: clkgate@48 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&pclk>;
+ clock-output-names = "clk_i2c0";
+ hisilicon,hi3620-clkgate = <0x40 0x1000000>;
+ };
+ i2cclk1: clkgate@49 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&pclk>;
+ clock-output-names = "clk_i2c1";
+ hisilicon,hi3620-clkgate = <0x40 0x2000000>;
+ };
+ i2cclk2: clkgate@50 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&pclk>;
+ clock-output-names = "clk_i2c2";
+ hisilicon,hi3620-clkgate = <0x40 0x10000000>;
+ };
+ i2cclk3: clkgate@51 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&pclk>;
+ clock-output-names = "clk_i2c3";
+ hisilicon,hi3620-clkgate = <0x40 0x20000000>;
+ };
+ dmaclk: clkgate@52 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&acpclk>;
+ clock-output-names = "clk_dmac";
+ hisilicon,hi3620-clkgate = <0x50 0x400>;
+ };
+ mcuclk: clkgate@53 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&refclk_cfgaxi>;
+ clock-output-names = "clk_mcu";
+ hisilicon,hi3620-clkgate = <0x50 0x1000000>;
+ };
+ ddrcperclk: clkgate@54 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&refclk_cfgaxi>;
+ clock-output-names = "clk_ddrc_per";
+ hisilicon,hi3620-clkgate = <0x50 0x200>;
+ };
+ acpclk: clkgate@55 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&refclk_cfgaxi>;
+ clock-output-names = "clk_apc";
+ hisilicon,hi3620-clkgate = <0x30 0x10000000>;
+ };
+ mmcclk1: clkgate@56 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&refclk_mmc1_parent>;
+ clock-output-names = "clk_mmc1";
+ hisilicon,hi3620-clkgate = <0x50 0x200000>;
+ };
+ mmcclk2: clkgate@57 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&div_mmc2>;
+ clock-output-names = "clk_mmc2";
+ hisilicon,hi3620-clkgate = <0x50 0x400000>;
+ };
+ mmcclk3: clkgate@58 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&div_mmc3>;
+ clock-output-names = "clk_mmc3";
+ hisilicon,hi3620-clkgate = <0x50 0x800000>;
+ };
+ sdclk: clkgate@59 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&div_sd>;
+ clock-output-names = "clk_sd";
+ hisilicon,hi3620-clkgate = <0x50 0x100000>;
+ };
+ kpcclk: clkgate@60 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&osc32k>;
+ clock-output-names = "clk_kpc";
+ hisilicon,hi3620-clkgate = <0x20 0x40>;
+ };
+ sciclk: clkgate@61 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&osc26m>;
+ clock-output-names = "clk_sci";
+ hisilicon,hi3620-clkgate = <0x40 0x4000000>;
+ };
+ dphyclk0: clkgate@62 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&osc26m>;
+ clock-output-names = "clk_dphy0";
+ hisilicon,hi3620-clkgate = <0x30 0x8000>;
+ };
+ dphyclk1: clkgate@63 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&osc26m>;
+ clock-output-names = "clk_dphy1";
+ hisilicon,hi3620-clkgate = <0x30 0x10000>;
+ };
+ dphyclk2: clkgate@64 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&osc26m>;
+ clock-output-names = "clk_dphy2";
+ hisilicon,hi3620-clkgate = <0x30 0x20000>;
+ };
+ ldiclk0: clkgate@65 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&refclk_ldi0>;
+ clock-output-names = "clk_ldi0";
+ hisilicon,hi3620-clkgate = <0x30 0x200>;
+ };
+ ldiclk1: clkgate@66 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&refclk_ldi1>;
+ clock-output-names = "clk_ldi1";
+ hisilicon,hi3620-clkgate = <0x30 0x800>;
+ };
+ edcclk0: clkgate@67 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&pclk>;
+ clock-output-names = "clk_edc0";
+ hisilicon,hi3620-clkgate = <0x30 0x100>;
+ };
+ edcclk1: clkgate@68 {
+ compatible = "hisilicon,hi3620-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&pclk>;
+ clock-output-names = "clk_edc1";
+ hisilicon,hi3620-clkgate = <0x30 0x400>;
+ };
+
+ dtable: clkdiv@0 {
+ #hisilicon,clkdiv-table-cells = <2>;
+ };
+
+ div_shareaxi: clkdiv@1 {
+ compatible = "hisilicon,hi3620-clk-div";
+ #clock-cells = <0>;
+ clocks = <&refclk_shareAXI>;
+ clock-output-names = "shareAXI_div";
+ hisilicon,clkdiv-table = <32 1>;
+ /* divider register offset, mask */
+ hisilicon,clkdiv = <0x100 0x1f>;
+ };
+ div_cfgaxi: clkdiv@2 {
+ compatible = "hisilicon,hi3620-clk-div";
+ #clock-cells = <0>;
+ clocks = <&div_shareaxi>;
+ clock-output-names = "cfgAXI_div";
+ hisilicon,clkdiv-table = <2 2>;
+ hisilicon,clkdiv = <0x100 0x60>;
+ };
+ div_mmc1: clkdiv@3 {
+ compatible = "hisilicon,hi3620-clk-div";
+ #clock-cells = <0>;
+ clocks = <&refclk_mmc1>;
+ clock-output-names = "div_mmc1";
+ hisilicon,clkdiv-table = <16 1>;
+ hisilicon,clkdiv = <0x108 0x1e0>;
+ };
+ div_mmc2: clkdiv@4 {
+ compatible = "hisilicon,hi3620-clk-div";
+ #clock-cells = <0>;
+ clocks = <&refclk_mmc2>;
+ clock-output-names = "div_mmc2";
+ hisilicon,clkdiv-table = <16 1>;
+ hisilicon,clkdiv = <0x140 0xf>;
+ };
+ div_mmc3: clkdiv@5 {
+ compatible = "hisilicon,hi3620-clk-div";
+ #clock-cells = <0>;
+ clocks = <&refclk_mmc3>;
+ clock-output-names = "div_mmc3";
+ hisilicon,clkdiv-table = <16 1>;
+ hisilicon,clkdiv = <0x140 0x1e0>;
+ };
+ div_sd: clkdiv@6 {
+ compatible = "hisilicon,hi3620-clk-div";
+ #clock-cells = <0>;
+ clocks = <&refclk_sd>;
+ clock-output-names = "div_sd";
+ hisilicon,clkdiv-table = <16 1>;
+ hisilicon,clkdiv = <0x108 0xf>;
+ };
+ pwm_divider: pwm_divider {
+ compatible = "hisilicon,hi3620-clk-div";
+ #clock-cells = <0>;
+ clocks = <&osc26m>;
+ clock-output-names = "pwm_divider";
+ hisilicon,clkdiv-table = <31 1>;
+ hisilicon,clkdiv = <0x104 0x3e0>;
+ };
+ };
+
+ rtc0: rtc@fc804000 {
+ compatible = "arm,rtc-pl031", "arm,primecell";
+ reg = <0xfc804000 0x1000>;
+ interrupts = <0 9 0x4>;
+ clocks = <&rtcclk>;
+ clock-names = "apb_pclk";
+ status = "disabled";
+ };
+
+ l2: l2-cache {
+ compatible = "arm,pl310-cache";
+ reg = <0xfc100000 0x100000>;
+ interrupts = <0 15 4>;
+ cache-unified;
+ cache-level = <2>;
+ };
+
+ intc: interrupt-controller@fc001000 {
+ compatible = "arm,cortex-a9-gic";
+ #interrupt-cells = <3>;
+ #address-cells = <0>;
+ interrupt-controller;
+ /* gic dist base, gic cpu base */
+ reg = <0xfc001000 0x1000>, <0xfc000100 0x100>;
+ };
+
+ dual_timer0: dual_timer@fc800000 {
+ compatible = "arm,sp804", "arm,primecell";
+ reg = <0xfc800000 0x1000>;
+ /* timer00 & timer01 */
+ interrupts = <0 0 4>, <0 1 4>;
+ clocks = <&timer0_mux &timer1_mux>;
+ clock-names = "apb_pclk";
+ status = "disabled";
+ };
+
+ dual_timer1: dual_timer@fc801000 {
+ /*
+ * Only used in NORMAL state, not available ins
+ * SLOW or DOZE state.
+ * The rate is fixed in 24MHz.
+ */
+ compatible = "arm,sp804", "arm,primecell";
+ reg = <0xfc801000 0x1000>;
+ /* timer10 & timer11 */
+ interrupts = <0 2 4>, <0 3 4>;
+ clocks = <&timer2_mux &timer3_mux>;
+ clock-names = "apb_pclk";
+ status = "disabled";
+ };
+
+ dual_timer2: dual_timer@fca01000 {
+ compatible = "arm,sp804", "arm,primecell";
+ reg = <0xfca01000 0x1000>;
+ /* timer20 & timer21 */
+ interrupts = <0 4 4>, <0 5 4>;
+ clocks = <&timer4_mux &timer5_mux>;
+ clock-names = "apb_pclk";
+ status = "disabled";
+ };
+
+ dual_timer3: dual_timer@fca02000 {
+ compatible = "arm,sp804", "arm,primecell";
+ reg = <0xfca02000 0x1000>;
+ /* timer30 & timer31 */
+ interrupts = <0 6 4>, <0 7 4>;
+ clocks = <&timer6_mux &timer7_mux>;
+ clock-names = "apb_pclk";
+ status = "disabled";
+ };
+
+
+ timer5: timer@fc000600 {
+ compatible = "arm,cortex-a9-twd-timer";
+ reg = <0xfc000600 0x20>;
+ interrupts = <1 13 0xf01>;
+ };
+
+ uart0: uart@fcb00000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0xfcb00000 0x1000>;
+ interrupts = <0 20 4>;
+ clocks = <&uartclk0>;
+ clock-names = "apb_pclk";
+ status = "disabled";
+ };
+
+ uart1: uart@fcb01000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0xfcb01000 0x1000>;
+ interrupts = <0 21 4>;
+ clocks = <&uartclk1>;
+ clock-names = "apb_pclk";
+ status = "disabled";
+ };
+
+ uart2: uart@fcb02000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0xfcb02000 0x1000>;
+ interrupts = <0 22 4>;
+ clocks = <&uartclk2>;
+ clock-names = "apb_pclk";
+ status = "disabled";
+ };
+
+ uart3: uart@fcb03000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0xfcb03000 0x1000>;
+ interrupts = <0 23 4>;
+ clocks = <&uartclk3>;
+ clock-names = "apb_pclk";
+ status = "disabled";
+ };
+
+ uart4: uart@fcb04000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0xfcb04000 0x1000>;
+ interrupts = <0 24 4>;
+ clocks = <&uartclk4>;
+ clock-names = "apb_pclk";
+ status = "disabled";
+ };
+
+ gpio0: gpio@fc806000 {
+ compatible = "arm,pl061", "arm,primecell";
+ reg = <0xfc806000 0x1000>;
+ interrupts = <0 64 0x4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = < &pmx0 2 0 1 &pmx0 3 0 1 &pmx0 4 0 1
+ &pmx0 5 0 1 &pmx0 6 1 1 &pmx0 7 2 1>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ clocks = <&gpioclk0>;
+ clock-names = "apb_pclk";
+ linux,gpio-base = <0>;
+ status = "disable";
+ };
+
+ gpio1: gpio@fc807000 {
+ compatible = "arm,pl061", "arm,primecell";
+ reg = <0xfc807000 0x1000>;
+ interrupts = <0 65 0x4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = < &pmx0 0 3 1 &pmx0 1 3 1 &pmx0 2 3 1
+ &pmx0 3 3 1 &pmx0 4 3 1 &pmx0 5 4 1
+ &pmx0 6 5 1 &pmx0 7 6 1>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ clocks = <&gpioclk1>;
+ clock-names = "apb_pclk";
+ linux,gpio-base = <8>;
+ status = "disable";
+ };
+
+ gpio2: gpio@fc808000 {
+ compatible = "arm,pl061", "arm,primecell";
+ reg = <0xfc808000 0x1000>;
+ interrupts = <0 66 0x4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = < &pmx0 0 7 1 &pmx0 1 8 1 &pmx0 2 9 1
+ &pmx0 3 10 1 &pmx0 4 3 1 &pmx0 5 3 1
+ &pmx0 6 3 1 &pmx0 7 3 1>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ clocks = <&gpioclk2>;
+ clock-names = "apb_pclk";
+ linux,gpio-base = <16>;
+ status = "disable";
+ };
+
+ gpio3: gpio@fc809000 {
+ compatible = "arm,pl061", "arm,primecell";
+ reg = <0xfc809000 0x1000>;
+ interrupts = <0 67 0x4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = < &pmx0 0 3 1 &pmx0 1 3 1 &pmx0 2 3 1
+ &pmx0 3 3 1 &pmx0 4 11 1 &pmx0 5 11 1
+ &pmx0 6 11 1 &pmx0 7 11 1>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ clocks = <&gpioclk3>;
+ clock-names = "apb_pclk";
+ linux,gpio-base = <24>;
+ status = "disable";
+ };
+
+ gpio4: gpio@fc80a000 {
+ compatible = "arm,pl061", "arm,primecell";
+ reg = <0xfc80a000 0x1000>;
+ interrupts = <0 68 0x4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = < &pmx0 0 11 1 &pmx0 1 11 1 &pmx0 2 11 1
+ &pmx0 3 11 1 &pmx0 4 12 1 &pmx0 5 12 1
+ &pmx0 6 13 1 &pmx0 7 13 1>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ clocks = <&gpioclk4>;
+ clock-names = "apb_pclk";
+ linux,gpio-base = <32>;
+ status = "disable";
+ };
+
+ gpio5: gpio@fc80b000 {
+ compatible = "arm,pl061", "arm,primecell";
+ reg = <0xfc80b000 0x1000>;
+ interrupts = <0 69 0x4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = < &pmx0 0 14 1 &pmx0 1 15 1 &pmx0 2 16 1
+ &pmx0 3 16 1 &pmx0 4 16 1 &pmx0 5 16 1
+ &pmx0 6 16 1 &pmx0 7 16 1>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ clocks = <&gpioclk5>;
+ clock-names = "apb_pclk";
+ linux,gpio-base = <40>;
+ status = "disable";
+ };
+
+ gpio6: gpio@fc80c000 {
+ compatible = "arm,pl061", "arm,primecell";
+ reg = <0xfc80c000 0x1000>;
+ interrupts = <0 70 0x4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = < &pmx0 0 16 1 &pmx0 1 16 1 &pmx0 2 17 1
+ &pmx0 3 17 1 &pmx0 4 18 1 &pmx0 5 18 1
+ &pmx0 6 18 1 &pmx0 7 19 1>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ clocks = <&gpioclk6>;
+ clock-names = "apb_pclk";
+ linux,gpio-base = <48>;
+ status = "disable";
+ };
+
+ gpio7: gpio@fc80d000 {
+ compatible = "arm,pl061", "arm,primecell";
+ reg = <0xfc80d000 0x1000>;
+ interrupts = <0 71 0x4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = < &pmx0 0 19 1 &pmx0 1 20 1 &pmx0 2 21 1
+ &pmx0 3 22 1 &pmx0 4 23 1 &pmx0 5 24 1
+ &pmx0 6 25 1 &pmx0 7 26 1>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ clocks = <&gpioclk7>;
+ clock-names = "apb_pclk";
+ linux,gpio-base = <56>;
+ status = "disable";
+ };
+
+ gpio8: gpio@fc80e000 {
+ compatible = "arm,pl061", "arm,primecell";
+ reg = <0xfc80e000 0x1000>;
+ interrupts = <0 72 0x4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = < &pmx0 0 27 1 &pmx0 1 28 1 &pmx0 2 29 1
+ &pmx0 3 30 1 &pmx0 4 31 1 &pmx0 5 32 1
+ &pmx0 6 33 1 &pmx0 7 34 1>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ clocks = <&gpioclk8>;
+ clock-names = "apb_pclk";
+ linux,gpio-base = <64>;
+ status = "disable";
+ };
+
+ gpio9: gpio@fc80f000 {
+ compatible = "arm,pl061", "arm,primecell";
+ reg = <0xfc80f000 0x1000>;
+ interrupts = <0 73 0x4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = < &pmx0 0 35 1 &pmx0 1 36 1 &pmx0 2 37 1
+ &pmx0 3 38 1 &pmx0 4 39 1 &pmx0 5 40 1
+ &pmx0 6 41 1>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ clocks = <&gpioclk9>;
+ clock-names = "apb_pclk";
+ linux,gpio-base = <72>;
+ status = "disable";
+ };
+
+ gpio10: gpio@fc810000 {
+ compatible = "arm,pl061", "arm,primecell";
+ reg = <0xfc810000 0x1000>;
+ interrupts = <0 74 0x4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = < &pmx0 2 43 1 &pmx0 3 44 1 &pmx0 4 45 1
+ &pmx0 5 45 1 &pmx0 6 46 1 &pmx0 7 46 1>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ clocks = <&gpioclk10>;
+ clock-names = "apb_pclk";
+ linux,gpio-base = <80>;
+ status = "disable";
+ };
+
+ gpio11: gpio@fc811000 {
+ compatible = "arm,pl061", "arm,primecell";
+ reg = <0xfc811000 0x1000>;
+ interrupts = <0 75 0x4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = < &pmx0 0 47 1 &pmx0 1 47 1 &pmx0 2 47 1
+ &pmx0 3 47 1 &pmx0 4 47 1 &pmx0 5 48 1
+ &pmx0 6 49 1 &pmx0 7 49 1>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ clocks = <&gpioclk11>;
+ clock-names = "apb_pclk";
+ linux,gpio-base = <88>;
+ status = "disable";
+ };
+
+ gpio12: gpio@fc812000 {
+ compatible = "arm,pl061", "arm,primecell";
+ reg = <0xfc812000 0x1000>;
+ interrupts = <0 76 0x4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = < &pmx0 0 49 1 &pmx0 1 50 1 &pmx0 2 49 1
+ &pmx0 3 49 1 &pmx0 4 51 1 &pmx0 5 51 1
+ &pmx0 6 51 1 &pmx0 7 52 1>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ clocks = <&gpioclk12>;
+ clock-names = "apb_pclk";
+ linux,gpio-base = <96>;
+ status = "disable";
+ };
+
+ gpio13: gpio@fc813000 {
+ compatible = "arm,pl061", "arm,primecell";
+ reg = <0xfc813000 0x1000>;
+ interrupts = <0 77 0x4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = < &pmx0 0 51 1 &pmx0 1 51 1 &pmx0 2 53 1
+ &pmx0 3 53 1 &pmx0 4 53 1 &pmx0 5 54 1
+ &pmx0 6 55 1 &pmx0 7 56 1>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ clocks = <&gpioclk13>;
+ clock-names = "apb_pclk";
+ linux,gpio-base = <104>;
+ status = "disable";
+ };
+
+ gpio14: gpio@fc814000 {
+ compatible = "arm,pl061", "arm,primecell";
+ reg = <0xfc814000 0x1000>;
+ interrupts = <0 78 0x4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = < &pmx0 0 57 1 &pmx0 1 97 1 &pmx0 2 97 1
+ &pmx0 3 58 1 &pmx0 4 59 1 &pmx0 5 60 1
+ &pmx0 6 60 1 &pmx0 7 61 1>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ clocks = <&gpioclk14>;
+ clock-names = "apb_pclk";
+ linux,gpio-base = <112>;
+ status = "disable";
+ };
+
+ gpio15: gpio@fc815000 {
+ compatible = "arm,pl061", "arm,primecell";
+ reg = <0xfc815000 0x1000>;
+ interrupts = <0 79 0x4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = < &pmx0 0 61 1 &pmx0 1 62 1 &pmx0 2 62 1
+ &pmx0 3 63 1 &pmx0 4 63 1 &pmx0 5 64 1
+ &pmx0 6 64 1 &pmx0 7 65 1>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ clocks = <&gpioclk15>;
+ clock-names = "apb_pclk";
+ linux,gpio-base = <120>;
+ status = "disable";
+ };
+
+ gpio16: gpio@fc816000 {
+ compatible = "arm,pl061", "arm,primecell";
+ reg = <0xfc816000 0x1000>;
+ interrupts = <0 80 0x4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = < &pmx0 0 66 1 &pmx0 1 67 1 &pmx0 2 68 1
+ &pmx0 3 69 1 &pmx0 4 70 1 &pmx0 5 71 1
+ &pmx0 6 72 1 &pmx0 7 73 1>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ clocks = <&gpioclk16>;
+ clock-names = "apb_pclk";
+ linux,gpio-base = <128>;
+ status = "disable";
+ };
+
+ gpio17: gpio@fc817000 {
+ compatible = "arm,pl061", "arm,primecell";
+ reg = <0xfc817000 0x1000>;
+ interrupts = <0 81 0x4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = < &pmx0 0 74 1 &pmx0 1 75 1 &pmx0 2 76 1
+ &pmx0 3 77 1 &pmx0 4 78 1 &pmx0 5 79 1
+ &pmx0 6 80 1 &pmx0 7 81 1>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ clocks = <&gpioclk17>;
+ clock-names = "apb_pclk";
+ linux,gpio-base = <136>;
+ status = "disable";
+ };
+
+ gpio18: gpio@fc818000 {
+ compatible = "arm,pl061", "arm,primecell";
+ reg = <0xfc818000 0x1000>;
+ interrupts = <0 82 0x4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = < &pmx0 0 82 1 &pmx0 1 83 1 &pmx0 2 83 1
+ &pmx0 3 84 1 &pmx0 4 84 1 &pmx0 5 85 1
+ &pmx0 6 86 1 &pmx0 7 87 1>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ clocks = <&gpioclk18>;
+ clock-names = "apb_pclk";
+ linux,gpio-base = <144>;
+ status = "disable";
+ };
+
+ gpio19: gpio@fc819000 {
+ compatible = "arm,pl061", "arm,primecell";
+ reg = <0xfc819000 0x1000>;
+ interrupts = <0 83 0x4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = < &pmx0 0 87 1 &pmx0 1 87 1 &pmx0 2 88 1
+ &pmx0 3 88 1>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ clocks = <&gpioclk19>;
+ clock-names = "apb_pclk";
+ linux,gpio-base = <152>;
+ status = "disable";
+ };
+
+ gpio20: gpio@fc81a000 {
+ compatible = "arm,pl061", "arm,primecell";
+ reg = <0xfc81a000 0x1000>;
+ interrupts = <0 84 0x4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = < &pmx0 0 89 1 &pmx0 1 89 1 &pmx0 2 90 1
+ &pmx0 3 90 1 &pmx0 4 91 1 &pmx0 5 92 1>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ clocks = <&gpioclk20>;
+ clock-names = "apb_pclk";
+ linux,gpio-base = <160>;
+ status = "disable";
+ };
+
+ gpio21: gpio@fc81b000 {
+ compatible = "arm,pl061", "arm,primecell";
+ reg = <0xfc81b000 0x1000>;
+ interrupts = <0 85 0x4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = < &pmx0 3 94 1 &pmx0 7 96 1>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ clocks = <&gpioclk21>;
+ clock-names = "apb_pclk";
+ linux,gpio-base = <168>;
+ status = "disable";
+ };
+
+ pmx0: pinmux@fc803000 {
+ compatible = "pinctrl-single";
+ reg = <0xfc803000 0x188>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ #gpio-range-cells = <3>;
+ ranges;
+
+ pinctrl-single,register-width = <32>;
+ pinctrl-single,function-mask = <7>;
+ /* pin base, nr pins & gpio function */
+ pinctrl-single,gpio-range = <&range 0 3 0 &range 3 9 1
+ &range 12 1 0 &range 13 29 1
+ &range 43 1 0 &range 44 49 1
+ &range 94 1 1 &range 96 2 1>;
+
+ range: gpio-range {
+ #pinctrl-single,gpio-range-cells = <3>;
+ };
+ };
+
+ pmx1: pinmux@fc803800 {
+ compatible = "pinconf-single";
+ reg = <0xfc803800 0x2dc>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ pinctrl-single,register-width = <32>;
+ };
+
+ i2c0: i2c@fcb08000 {
+ compatible = "snps,designware-i2c";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0xfcb08000 0x1000>;
+ interrupts = <0 28 4>;
+ clocks = <&i2cclk0>;
+ status = "disabled";
+ };
+
+ i2c1: i2c@fcb09000 {
+ compatible = "snps,designware-i2c";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0xfcb09000 0x1000>;
+ interrupts = <0 29 4>;
+ clocks = <&i2cclk1>;
+ status = "disabled";
+ };
+
+ i2c2: i2c@fcb0c000 {
+ compatible = "snps,designware-i2c";
+ reg = <0xfcb0c000 0x1000>;
+ interrupts = <0 62 4>;
+ clocks = <&i2cclk2>;
+ status = "disabled";
+ };
+
+ i2c3: i2c@fcb0d000 {
+ compatible = "snps,designware-i2c";
+ reg = <0xfcb0d000 0x1000>;
+ interrupts = <0 63 4>;
+ clocks = <&i2cclk3>;
+ status = "disabled";
+ };
+
+ /* unremovable emmc as mmcblk0 */
+ dwmmc_1: dwmmc1@fcd04000 {
+ compatible = "hisilicon,hi4511-dw-mshc";
+ reg = <0xfcd04000 0x1000>;
+ interrupts = <0 17 4>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clocks = <&mmcclk1>, <&ddrcperclk>;
+ clock-names = "ciu", "biu";
+ };
+
+ /* sd as mmcblk1 */
+ dwmmc_0: dwmmc0@fcd03000 {
+ compatible = "hisilicon,hi4511-dw-mshc";
+ reg = <0xfcd03000 0x1000>;
+ interrupts = <0 16 4>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clocks = <&sdclk>, <&ddrcperclk>;
+ clock-names = "ciu", "biu";
+ };
+
+ dwmmc_2: dwmmc2@fcd05000 {
+ compatible = "hisilicon,hi4511-dw-mshc";
+ reg = <0xfcd05000 0x1000>;
+ interrupts = <0 18 4>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clocks = <&mmcclk2>;
+ };
+
+ dwmmc_3: dwmmc3@fcd06000 {
+ compatible = "hisilicon,hi4511-dw-mshc";
+ reg = <0xfcd06000 0x1000>;
+ interrupts = <0 19 4>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clocks = <&mmcclk3>;
+ };
+
+ dma0: dma@fcd02000 {
+ compatible = "hisilicon,k3-dma-1.0";
+ reg = <0xfcd02000 0x1000>;
+ #dma-cells = <1>;
+ dma-channels = <16>;
+ dma-requests = <27>;
+ interrupts = <0 12 4>;
+ clocks = <&dmaclk>;
+ status = "disable";
+ };
+
+ edc0: edc@fa202000 {
+ compatible = "hisilicon,hi3620-fb";
+ reg = <0xfa202000 0x1000>;
+ clocks = <&ldiclk0 &edcclk0 &dsiclk0 &lanebyteclk0>;
+ clock-names = "ldi", "edc", "dsi", "lane";
+ interrupts = <0 38 0x4>, <0 39 0x4>, <0 40 0x4>;
+ interrupt-names = "edc", "ldi", "dsi";
+ status = "disabled";
+
+ dsi2xclk0: clkdsi@0 {
+ compatible = "hisilicon,hi3620-phy";
+ #clock-cells = <0>;
+ clocks = <&osc26m>;
+ clock-output-names = "clk_dsi2x0";
+ };
+ dsiclk0: clkdsi@1 {
+ compatible = "hisilicon,clk-fixed-factor";
+ #clock-cells = <0>;
+ clocks = <&dsi2xclk0>;
+ clock-output-names = "clk_dsi0";
+ /*mult, div*/
+ hisilicon,fixed-factor = <1 2>;
+ };
+ lanebyteclk0: clkdsi@2 {
+ compatible = "hisilicon,clk-fixed-factor";
+ #clock-cells = <0>;
+ clocks = <&dsi2xclk0>;
+ clock-output-names = "clk_lanebyte0";
+ /*mult, div*/
+ hisilicon,fixed-factor = <1 8>;
+ };
+ escclk0: clkdsi@3 {
+ compatible = "hisilicon,hi3620-phy-esc";
+ #clock-cells = <0>;
+ clocks = <&lanebyteclk0>;
+ clock-output-names = "clk_dsi_phy_esc0";
+ };
+ };
+
+ edc1: edc@fa206900 {
+ compatible = "hisilicon,hi3620-fb";
+ clocks = <&ldiclk1 &edcclk1>;
+ clock-names = "ldi", "edc";
+ status = "disabled";
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/hi3716-dkb.dts b/arch/arm/boot/dts/hi3716-dkb.dts
new file mode 100644
index 000000000000..86fae4a783aa
--- /dev/null
+++ b/arch/arm/boot/dts/hi3716-dkb.dts
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2013 Linaro Ltd.
+ * Copyright (c) 2013 Hisilicon Limited.
+ *
+ * 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
+ * publishhed by the Free Software Foundation.
+ */
+
+/dts-v1/;
+/include/ "hi3716.dtsi"
+
+/ {
+ model = "Hisilicon Hi3716 Development Board";
+ compatible = "hisilicon,hi3716";
+
+ chosen {
+ bootargs = "console=ttyAMA0,115200";
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ compatible = "arm,cortex-a9";
+ device_type = "cpu";
+ reg = <0>;
+ next-level-cache = <&l2>;
+ };
+
+ cpu@1 {
+ compatible = "arm,cortex-a9";
+ device_type = "cpu";
+ reg = <1>;
+ next-level-cache = <&l2>;
+ };
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x00000000 0x80000000>;
+ };
+
+ soc {
+ amba {
+ timer0: timer@f8002000 {
+ status = "okay";
+ };
+
+ uart0: uart@f8b00000 {
+ status = "okay";
+ };
+
+ dmac: dmac@f9870000 {
+ status = "okay";
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/hi3716.dtsi b/arch/arm/boot/dts/hi3716.dtsi
new file mode 100644
index 000000000000..591d4316749c
--- /dev/null
+++ b/arch/arm/boot/dts/hi3716.dtsi
@@ -0,0 +1,280 @@
+/*
+ * Copyright (c) 2013 Linaro Ltd.
+ * Copyright (c) 2013 Hisilicon Limited.
+ *
+ * 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
+ * publishhed by the Free Software Foundation.
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+ aliases {
+ serial0 = &uart0;
+ };
+
+ gic: interrupt-controller@fc001000 {
+ compatible = "arm,cortex-a9-gic";
+ #interrupt-cells = <3>;
+ #address-cells = <0>;
+ interrupt-controller;
+ /* gic dist base, gic cpu base */
+ reg = <0xf8a01000 0x1000>, <0xf8a00100 0x100>;
+ };
+
+ soc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "simple-bus";
+ device_type = "soc";
+ interrupt-parent = <&gic>;
+ ranges;
+
+ amba {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "arm,amba-bus";
+ ranges;
+
+ timer0: timer@f8002000 {
+ compatible = "arm,sp804", "arm,primecell";
+ reg = <0xf8002000 0x1000>;
+ /* timer00 & timer01 */
+ interrupts = <0 24 4>;
+ clocks = <&osc24m>;
+ status = "disabled";
+ };
+
+ timer1: timer@f8a29000 {
+ /*
+ * Only used in NORMAL state, not available ins
+ * SLOW or DOZE state.
+ * The rate is fixed in 24MHz.
+ */
+ compatible = "arm,sp804", "arm,primecell";
+ reg = <0xf8a29000 0x1000>;
+ /* timer10 & timer11 */
+ interrupts = <0 25 4>;
+ clocks = <&osc24m>;
+ status = "disabled";
+ };
+
+ timer2: timer@f8a2a000 {
+ compatible = "arm,sp804", "arm,primecell";
+ reg = <0xf8a2a000 0x1000>;
+ /* timer20 & timer21 */
+ interrupts = <0 26 4>;
+ clocks = <&osc24m>;
+ status = "disabled";
+ };
+
+ timer3: timer@f8a2b000 {
+ compatible = "arm,sp804", "arm,primecell";
+ reg = <0xf8a2b000 0x1000>;
+ /* timer30 & timer31 */
+ interrupts = <0 27 4>;
+ clocks = <&osc24m>;
+ status = "disabled";
+ };
+
+ timer4: timer@f8a81000 {
+ compatible = "arm,sp804", "arm,primecell";
+ reg = <0xf8a81000 0x1000>;
+ /* timer30 & timer31 */
+ interrupts = <0 28 4>;
+ clocks = <&osc24m>;
+ status = "disabled";
+ };
+
+ uart0: uart@f8b00000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0xf8b00000 0x1000>;
+ interrupts = <0 49 4>;
+ clocks = <&bpll_fout0_div 1>;
+ clock-names = "apb_pclk";
+ status = "disabled";
+ };
+
+ uart1: uart@f8006000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0xf8006000 0x1000>;
+ interrupts = <0 50 4>;
+ clocks = <&bpll_fout0_div 1>;
+ clock-names = "apb_pclk";
+ status = "disabled";
+ };
+
+ uart2: uart@f8b02000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0xf8b02000 0x1000>;
+ interrupts = <0 51 4>;
+ clocks = <&bpll_fout0_div 1>;
+ clock-names = "apb_pclk";
+ status = "disabled";
+ };
+
+ uart3: uart@f8b03000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0xf8b03000 0x1000>;
+ interrupts = <0 52 4>;
+ clocks = <&bpll_fout0_div 1>;
+ clock-names = "apb_pclk";
+ status = "disabled";
+ };
+
+ uart4: uart@f8b04000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0xf8b04000 0x1000>;
+ interrupts = <0 53 4>;
+ clocks = <&bpll_fout0_div 1>;
+ clock-names = "apb_pclk";
+ status = "disabled";
+ };
+
+ dmac: dmac@f9870000 {
+ compatible = "arm,pl080", "arm,primecell";
+ arm,primecell-periphid = <0x00041080>;
+ reg = <0xf9870000 0x1000>;
+ #dma-cells = <1>;
+ dma-channels = <8>;
+ dma-requests = <16>;
+ clocks = <&clk_dmac>;
+ clock-names = "apb_pclk";
+ interrupts = <0 30 4>;
+ status = "disabled";
+ };
+ };
+
+ clocks {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ osc24m: osc {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <24000000>;
+ clock-output-names = "osc24mhz";
+ };
+
+ bpll: bpll {
+ compatible = "hisilicon,hi3716-fixed-pll";
+ #clock-cells = <1>;
+ clocks = <&osc24m>;
+ clock-frequency = <1200000000>,
+ <600000000>,
+ <300000000>,
+ <200000000>,
+ <150000000>;
+ clock-output-names = "bpll_fout0",
+ "bpll_fout1",
+ "bpll_fout2",
+ "bpll_fout3",
+ "bpll_fout4";
+ };
+
+ bpll_fout0_div: bpll_fout0_div {/* 1200Mhz */
+ compatible = "hisilicon,hi3716-fixed-divider";
+ #clock-cells = <1>;
+ clocks = <&bpll 0>;
+ div-table = <3 14 25 50>;
+ clock-output-names = "fout0_400m", "fout0_86m",
+ "fout0_48m", "fout0_24m";
+ };
+
+ bpll_fout1_div: bpll_fout1_div {
+ compatible = "hisilicon,hi3716-fixed-divider";
+ #clock-cells = <0>;
+ clocks = <&bpll 1>;
+ div-table = <10>;
+ clock-output-names = "fout1_60m";
+ };
+
+ bpll_fout2_div: bpll_fout2_div {
+ compatible = "hisilicon,hi3716-fixed-divider";
+ #clock-cells = <0>;
+ clocks = <&bpll 2>;
+ div-table = <4>;
+ clock-output-names = "fout2_75m";
+ };
+
+ bpll_fout3_div: bpll_fout3_div {
+ compatible = "hisilicon,hi3716-fixed-divider";
+ #clock-cells = <1>;
+ clocks = <&bpll 3>;
+ div-table = <2 4 5 8>;
+ clock-output-names = "fout3_100m", "fout3_50m",
+ "fout3_40m", "fout3_25m";
+ };
+
+ clk_sfc_mux: clk_sfc_mux {
+ compatible = "hisilicon,hi3716-clk-mux";
+ #clock-cells = <0>;
+ /* clks: 24M 75M 100M 150M 200M */
+ clocks = <&osc24m>, <&bpll_fout2_div>,
+ <&bpll_fout3_div 0>, <&bpll 4>, <&bpll 3>;
+
+ /* offset mux_shift mux_width */
+ mux-reg = <0x5c 8 3>;
+ /* mux reg value to choose clks */
+ mux-table = <0 7 6 4 5>;
+
+ clock-output-names = "sfc_mux";
+ };
+
+ clk_sfc: clk_sfc {
+ compatible = "hisilicon,hi3716-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&clk_sfc_mux>;
+
+ /* offset, enable, reset */
+ gate-reg = <0x5c 0 4>;
+
+ clock-output-names = "sfc";
+ };
+
+ clk_dmac: clk_dmac {
+ compatible = "hisilicon,hi3716-clk-gate";
+ #clock-cells = <0>;
+ clocks = <&bpll 3>;
+
+ /* offset, enable, reset */
+ gate-reg = <0xa4 0 4>;
+
+ clock-output-names = "dmac";
+ };
+ };
+
+ local_timer@f8a00600 {
+ compatible = "arm,cortex-a9-twd-timer";
+ reg = <0xf8a00600 0x20>;
+ interrupts = <1 13 0xf01>;
+ };
+
+ l2: l2-cache {
+ compatible = "arm,pl310-cache";
+ reg = <0xf8a10000 0x100000>;
+ interrupts = <0 15 4>;
+ cache-unified;
+ cache-level = <2>;
+ hisilicon,l2cache-aux = <0x00050000 0xfff0ffff>;
+ };
+
+ sctrl@f8000000 {
+ compatible = "hisilicon,sctrl";
+ reg = <0xf8000000 0x1000>;
+ smp_reg = <0xc0>;
+ reboot_reg = <0x4>;
+ };
+
+ clkbase@f8a22000 {
+ compatible = "hisilicon,clkbase";
+ reg = <0xf8a22000 0x1000>;
+ };
+
+ cpuctrl@f8a22000 {
+ compatible = "hisilicon,cpuctrl";
+ reg = <0xf8a22000 0x2000>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/hi4511.dts b/arch/arm/boot/dts/hi4511.dts
new file mode 100644
index 000000000000..2e85f395cd43
--- /dev/null
+++ b/arch/arm/boot/dts/hi4511.dts
@@ -0,0 +1,1478 @@
+/*
+ * Copyright (C) 2012-2013 Linaro Ltd.
+ * Author: Haojian Zhuang <haojian.zhuang@linaro.org>
+ *
+ * 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
+ * publishhed by the Free Software Foundation.
+ */
+
+/dts-v1/;
+/include/ "hi3620.dtsi"
+
+/ {
+ model = "Hisilicon Hi4511 Development Board";
+ compatible = "hisilicon,hi3620-hi4511";
+
+ chosen {
+ bootargs = "console=ttyAMA0,115200 root=/dev/ram0 earlyprintk no_console_suspend";
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ compatible = "arm,cortex-a9";
+ device_type = "cpu";
+ reg = <0>;
+ next-level-cache = <&l2>;
+ };
+
+ cpu@1 {
+ compatible = "arm,cortex-a9";
+ device_type = "cpu";
+ reg = <1>;
+ next-level-cache = <&l2>;
+ };
+
+ cpu@2 {
+ compatible = "arm,cortex-a9";
+ device_type = "cpu";
+ reg = <2>;
+ next-level-cache = <&l2>;
+ };
+
+ cpu@3 {
+ compatible = "arm,cortex-a9";
+ device_type = "cpu";
+ reg = <3>;
+ next-level-cache = <&l2>;
+ };
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x40000000 0x20000000>;
+ };
+
+ amba {
+ dual_timer0: dual_timer@fc800000 {
+ status = "ok";
+ };
+
+ dma0: dma@fcd02000 {
+ status = "ok";
+ };
+
+ uart0: uart@fcb00000 { /* console */
+ /*
+ pinctrl-names = "default", "idle";
+ pinctrl-0 = <&uart0_pmx_func &uart0_cfg_func>;
+ pinctrl-1 = <&uart0_pmx_idle &uart0_cfg_idle>;
+ */
+ status = "ok";
+ };
+
+ uart1: uart@fcb01000 { /* modem */
+ pinctrl-names = "default", "idle";
+ pinctrl-0 = <&uart1_pmx_func &uart1_cfg_func>;
+ pinctrl-1 = <&uart1_pmx_idle &uart1_cfg_idle>;
+ status = "ok";
+ };
+
+ uart2: uart@fcb02000 { /* audience */
+ pinctrl-names = "default", "idle";
+ pinctrl-0 = <&uart2_pmx_func &uart2_cfg_func>;
+ pinctrl-1 = <&uart2_pmx_idle &uart2_cfg_idle>;
+ status = "ok";
+ };
+
+ uart3: uart@fcb03000 {
+ pinctrl-names = "default", "idle";
+ pinctrl-0 = <&uart3_pmx_func &uart3_cfg_func>;
+ pinctrl-1 = <&uart3_pmx_idle &uart3_cfg_idle>;
+ status = "ok";
+ };
+
+ uart4: uart@fcb04000 {
+ pinctrl-names = "default", "idle";
+ pinctrl-0 = <&uart4_pmx_func &uart4_cfg_func>;
+ pinctrl-1 = <&uart4_pmx_idle &uart4_cfg_func>;
+ status = "ok";
+ };
+
+ rtc0: rtc@fc804000 {
+ status = "ok";
+ };
+
+ gpio0: gpio@fc806000 {
+ status = "ok";
+ };
+
+ gpio1: gpio@fc807000 {
+ status = "ok";
+ };
+
+ gpio2: gpio@fc808000 {
+ status = "ok";
+ };
+
+ gpio3: gpio@fc809000 {
+ status = "ok";
+ };
+
+ gpio4: gpio@fc80a000 {
+ status = "ok";
+ };
+
+ gpio5: gpio@fc80b000 {
+ status = "ok";
+ };
+
+ gpio6: gpio@fc80c000 {
+ status = "ok";
+ };
+
+ gpio7: gpio@fc80d000 {
+ status = "ok";
+ };
+
+ gpio8: gpio@fc80e000 {
+ status = "ok";
+ };
+
+ gpio9: gpio@fc80f000 {
+ status = "ok";
+ };
+
+ gpio10: gpio@fc810000 {
+ status = "ok";
+ };
+
+ gpio11: gpio@fc811000 {
+ status = "ok";
+ };
+
+ gpio12: gpio@fc812000 {
+ status = "ok";
+ };
+
+ gpio13: gpio@fc813000 {
+ status = "ok";
+ };
+
+ gpio14: gpio@fc814000 {
+ status = "ok";
+ };
+
+ gpio15: gpio@fc815000 {
+ status = "ok";
+ };
+
+ gpio16: gpio@fc816000 {
+ status = "ok";
+ };
+
+ gpio17: gpio@fc817000 {
+ status = "ok";
+ };
+
+ gpio18: gpio@fc818000 {
+ status = "ok";
+ };
+
+ gpio19: gpio@fc819000 {
+ status = "ok";
+ };
+
+ gpio20: gpio@fc81a000 {
+ status = "ok";
+ };
+
+ gpio21: gpio@fc81b000 {
+ status = "ok";
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+
+ call {
+ label = "call";
+ gpios = <&gpio17 2 0>;
+ linux,code = <169>; /* KEY_PHONE */
+ };
+ };
+
+ pmx0: pinmux@fc803000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&board_pmx_pins>;
+
+ board_pmx_pins: pinmux_board_pmx_pins {
+ pinctrl-single,pins = <
+ 0x008 0x0 /* GPIO -- eFUSE_DOUT */
+ 0x100 0x0 /* USIM_CLK & USIM_DATA (IOMG63) */
+ >;
+ };
+ sd_pmx_pins: pinmux_sd_pins {
+ pinctrl-single,pins = <
+ 0x0bc 0x0 /* SD_CLK, SD_CMD, SD_DATA[0:2] */
+ 0x0c0 0x0 /* SD_DATA[3] */
+ >;
+ };
+ uart0_pmx_func: pinmux_uart0_func {
+ pinctrl-single,pins = <
+ 0x0f0 0x0
+ 0x0f4 0x0 /* UART0_RX & UART0_TX */
+ >;
+ };
+ uart0_pmx_idle: pinmux_uart0_idle {
+ pinctrl-single,pins = <
+ /*0x0f0 0x1*/ /* UART0_CTS & UART0_RTS */
+ 0x0f4 0x1 /* UART0_RX & UART0_TX */
+ >;
+ };
+ uart1_pmx_func: pinmux_uart1_func {
+ pinctrl-single,pins = <
+ 0x0f8 0x0 /* UART1_CTS & UART1_RTS (IOMG61) */
+ 0x0fc 0x0 /* UART1_RX & UART1_TX (IOMG62) */
+ >;
+ };
+ uart1_pmx_idle: pinmux_uart1_idle {
+ pinctrl-single,pins = <
+ 0x0f8 0x1 /* GPIO (IOMG61) */
+ 0x0fc 0x1 /* GPIO (IOMG62) */
+ >;
+ };
+ uart2_pmx_func: pinmux_uart2_func {
+ pinctrl-single,pins = <
+ 0x104 0x2 /* UART2_RXD (IOMG96) */
+ 0x108 0x2 /* UART2_TXD (IOMG64) */
+ >;
+ };
+ uart2_pmx_idle: pinmux_uart2_idle {
+ pinctrl-single,pins = <
+ 0x104 0x1 /* GPIO (IOMG96) */
+ 0x108 0x1 /* GPIO (IOMG64) */
+ >;
+ };
+ uart3_pmx_func: pinmux_uart3_func {
+ pinctrl-single,pins = <
+ 0x160 0x2 /* UART3_CTS & UART3_RTS (IOMG85) */
+ 0x164 0x2 /* UART3_RXD & UART3_TXD (IOMG86) */
+ >;
+ };
+ uart3_pmx_idle: pinmux_uart3_idle {
+ pinctrl-single,pins = <
+ 0x160 0x1 /* GPIO (IOMG85) */
+ 0x164 0x1 /* GPIO (IOMG86) */
+ >;
+ };
+ uart4_pmx_func: pinmux_uart4_func {
+ pinctrl-single,pins = <
+ 0x168 0x0 /* UART4_CTS & UART4_RTS (IOMG87) */
+ 0x16c 0x0 /* UART4_RXD (IOMG88) */
+ 0x170 0x0 /* UART4_TXD (IOMG93) */
+ >;
+ };
+ uart4_pmx_idle: pinmux_uart4_idle {
+ pinctrl-single,pins = <
+ 0x168 0x1 /* GPIO (IOMG87) */
+ 0x16c 0x1 /* GPIO (IOMG88) */
+ 0x170 0x1 /* GPIO (IOMG93) */
+ >;
+ };
+ i2c0_pmx_func: pinmux_i2c0_func {
+ pinctrl-single,pins = <
+ 0x0b4 0x0 /* I2C0_SCL & I2C0_SDA (IOMG45) */
+ >;
+ };
+ i2c0_pmx_idle: pinmux_i2c0_idle {
+ pinctrl-single,pins = <
+ 0x0b4 0x1 /* GPIO (IOMG45) */
+ >;
+ };
+ i2c1_pmx_func: pinmux_i2c1_func {
+ pinctrl-single,pins = <
+ 0x0b8 0x0 /* I2C1_SCL & I2C1_SDA (IOMG46) */
+ >;
+ };
+ i2c1_pmx_idle: pinmux_i2c1_idle {
+ pinctrl-single,pins = <
+ 0x0b8 0x1 /* GPIO (IOMG46) */
+ >;
+ };
+ i2c2_pmx_func: pinmux_i2c2_func {
+ pinctrl-single,pins = <
+ 0x068 0x0 /* I2C2_SCL (IOMG26) */
+ 0x06c 0x0 /* I2C2_SDA (IOMG27) */
+ >;
+ };
+ i2c2_pmx_idle: pinmux_i2c2_idle {
+ pinctrl-single,pins = <
+ 0x068 0x1 /* GPIO (IOMG26) */
+ 0x06c 0x1 /* GPIO (IOMG27) */
+ >;
+ };
+ i2c3_pmx_func: pinmux_i2c3_func {
+ pinctrl-single,pins = <
+ 0x050 0x2 /* I2C3_SCL (IOMG20) */
+ 0x054 0x2 /* I2C3_SDA (IOMG21) */
+ >;
+ };
+ i2c3_pmx_idle: pinmux_i2c3_idle {
+ pinctrl-single,pins = <
+ 0x050 0x1 /* GPIO (IOMG20) */
+ 0x054 0x1 /* GPIO (IOMG21) */
+ >;
+ };
+ spi0_pmx_func: pinmux_spi0_func {
+ pinctrl-single,pins = <
+ 0x0d4 0x0 /* SPI0_CLK/SPI0_DI/SPI0_DO (IOMG53) */
+ 0x0d8 0x0 /* SPI0_CS0 (IOMG54) */
+ 0x0dc 0x0 /* SPI0_CS1 (IOMG55) */
+ 0x0e0 0x0 /* SPI0_CS2 (IOMG56) */
+ 0x0e4 0x0 /* SPI0_CS3 (IOMG57) */
+ >;
+ };
+ spi0_pmx_idle: pinmux_spi0_idle {
+ pinctrl-single,pins = <
+ 0x0d4 0x1 /* GPIO (IOMG53) */
+ 0x0d8 0x1 /* GPIO (IOMG54) */
+ 0x0dc 0x1 /* GPIO (IOMG55) */
+ 0x0e0 0x1 /* GPIO (IOMG56) */
+ 0x0e4 0x1 /* GPIO (IOMG57) */
+ >;
+ };
+ spi1_pmx_func: pinmux_spi1_func {
+ pinctrl-single,pins = <
+ 0x184 0x0 /* SPI1_CLK/SPI1_DI (IOMG98) */
+ 0x0e8 0x0 /* SPI1_DO (IOMG58) */
+ 0x0ec 0x0 /* SPI1_CS (IOMG95) */
+ >;
+ };
+ spi1_pmx_idle: pinmux_spi1_idle {
+ pinctrl-single,pins = <
+ 0x184 0x1 /* GPIO (IOMG98) */
+ 0x0e8 0x1 /* GPIO (IOMG58) */
+ 0x0ec 0x1 /* GPIO (IOMG95) */
+ >;
+ };
+ kpc_pmx_func: pinmux_kpc_func {
+ pinctrl-single,pins = <
+ 0x12c 0x0 /* KEY_IN0 (IOMG73) */
+ 0x130 0x0 /* KEY_IN1 (IOMG74) */
+ 0x134 0x0 /* KEY_IN2 (IOMG75) */
+ 0x10c 0x0 /* KEY_OUT0 (IOMG65) */
+ 0x110 0x0 /* KEY_OUT1 (IOMG66) */
+ 0x114 0x0 /* KEY_OUT2 (IOMG67) */
+ >;
+ };
+ gpio_key_func: pinmux_gpiokey_func {
+ pinctrl-single,pins = <
+ 0x10c 0x1 /* KEY_OUT0/GPIO (IOMG65) */
+ 0x130 0x1 /* KEY_IN1/GPIO (IOMG74) */
+ >;
+ };
+ emmc_pmx_func: pinmux_emmc_pins@0 {
+ pinctrl-single,pins = <
+ 0x030 0x2 /* eMMC_CMD/eMMC_CLK (IOMG12) */
+ 0x018 0x0 /* NAND_CS3_N (IOMG6) */
+ 0x024 0x0 /* NAND_BUSY2_N (IOMG8) */
+ 0x028 0x0 /* NAND_BUSY3_N (IOMG9) */
+ 0x02c 0x2 /* eMMC_DATA[0:7] (IOMG10) */
+ >;
+ };
+ emmc_pmx_idle: pinmux_emmc_pins@1 {
+ pinctrl-single,pins = <
+ 0x030 0x0 /* GPIO (IOMG12) */
+ 0x018 0x1 /* GPIO (IOMG6) */
+ 0x024 0x1 /* GPIO (IOMG8) */
+ 0x028 0x1 /* GPIO (IOMG9) */
+ 0x02c 0x1 /* GPIO (IOMG10) */
+ >;
+ };
+ sd_pmx_func: pinmux_sd_pins@0 {
+ pinctrl-single,pins = <
+ 0x0bc 0x0 /* SD_CLK/SD_CMD/SD_DATA0/SD_DATA1/SD_DATA2 (IOMG47) */
+ 0x0c0 0x0 /* SD_DATA3 (IOMG48) */
+ >;
+ };
+ sd_pmx_idle: pinmux_sd_pins@1 {
+ pinctrl-single,pins = <
+ 0x0bc 0x1 /* GPIO (IOMG47) */
+ 0x0c0 0x1 /* GPIO (IOMG48) */
+ >;
+ };
+ nand_pmx_func: pinmux_nand_func {
+ pinctrl-single,pins = <
+ 0x00c 0x0 /* NAND_ALE/NAND_CLE/.../NAND_DATA[0:7] (IOMG3) */
+ 0x010 0x0 /* NAND_CS1_N (IOMG4) */
+ 0x014 0x0 /* NAND_CS2_N (IOMG5) */
+ 0x018 0x0 /* NAND_CS3_N (IOMG6) */
+ 0x01c 0x0 /* NAND_BUSY0_N (IOMG94) */
+ 0x020 0x0 /* NAND_BUSY1_N (IOMG7) */
+ 0x024 0x0 /* NAND_BUSY2_N (IOMG8) */
+ 0x028 0x0 /* NAND_BUSY3_N (IOMG9) */
+ 0x02c 0x0 /* NAND_DATA[8:15] (IOMG10) */
+ >;
+ };
+ nand_pmx_idle: pinmux_nand_idle {
+ pinctrl-single,pins = <
+ 0x00c 0x1 /* GPIO (IOMG3) */
+ 0x010 0x1 /* GPIO (IOMG4) */
+ 0x014 0x1 /* GPIO (IOMG5) */
+ 0x018 0x1 /* GPIO (IOMG6) */
+ 0x01c 0x1 /* GPIO (IOMG94) */
+ 0x020 0x1 /* GPIO (IOMG7) */
+ 0x024 0x1 /* GPIO (IOMG8) */
+ 0x028 0x1 /* GPIO (IOMG9) */
+ 0x02c 0x1 /* GPIO (IOMG10) */
+ >;
+ };
+ sdio_pmx_func: pinmux_sdio_func {
+ pinctrl-single,pins = <
+ 0x0c4 0x0 /* SDIO_CLK/SDIO_CMD/SDIO_DATA[0:3] (IOMG49) */
+ >;
+ };
+ sdio_pmx_idle: pinmux_sdio_idle {
+ pinctrl-single,pins = <
+ 0x0c4 0x1 /* GPIO (IOMG49) */
+ >;
+ };
+ audio_out_pmx_func: pinmux_audio_func {
+ pinctrl-single,pins = <
+ 0x0f0 0x1 /* GPIO (IOMG59), audio spk & earphone */
+ >;
+ };
+ pwm0_pmx_func: pinmux_pwm0_func {
+ pinctrl-single,pins = <
+ 0x154 0x0 /* PWM0 (IOMG82) */
+ >;
+ };
+ pwm0_pmx_idle: pinmux_pwm0_idle {
+ pinctrl-single,pins = <
+ 0x154 0x1 /* GPIO149 (IOMG82) */
+ >;
+ };
+ pwm1_pmx_func: pinmux_pwm1_func {
+ pinctrl-single,pins = <
+ 0x158 0x0 /* PWM1 (IOMG83) */
+ >;
+ };
+ pwm1_pmx_idle: pinmux_pwm1_idle {
+ pinctrl-single,pins = <
+ 0x158 0x1 /* GPIO150 (IOMG83) */
+ >;
+ };
+
+ };
+
+ pmx1: pinmux@fc803800 {
+ pinctrl-names = "default";
+ pinctrl-0 = < &board_pu_pins &board_pd_pins &board_pd_ps_pins
+ &board_np_pins &board_ps_pins &kpc_cfg_func
+ &audio_out_cfg_func>;
+ board_pu_pins: pinmux_board_pu_pins {
+ pinctrl-single,pins = <
+ 0x014 0 /* GPIO_158 (IOCFG2) */
+ 0x01c 0 /* BOOT_MODE0 (IOCFG4) */
+ 0x020 0 /* BOOT_MODE1 (IOCFG5) */
+ >;
+ pinctrl-single,bias-pulldown = <0 2 0 2>;
+ pinctrl-single,bias-pullup = <1 1 0 1>;
+ };
+ board_pd_pins: pinmux_board_pd_pins {
+ pinctrl-single,pins = <
+ 0x038 0 /* eFUSE_DOUT (IOCFG11) */
+ 0x150 0 /* ISP_GPIO8 (IOCFG93) */
+ 0x154 0 /* ISP_GPIO9 (IOCFG94) */
+ >;
+ pinctrl-single,bias-pulldown = <2 2 0 2>;
+ pinctrl-single,bias-pullup = <0 1 0 1>;
+ };
+ board_pd_ps_pins: pinmux_board_pd_ps_pins {
+ pinctrl-single,pins = <
+ 0x2d8 0 /* CLK_OUT0 (IOCFG190) */
+ 0x004 0 /* PMU_SPI_DATA (IOCFG192) */
+ >;
+ pinctrl-single,bias-pulldown = <2 2 0 2>;
+ pinctrl-single,bias-pullup = <0 1 0 1>;
+ pinctrl-single,drive-strength = <0x30 0xf0>;
+ };
+ board_np_pins: pinmux_board_np_pins {
+ pinctrl-single,pins = <
+ 0x24c 0 /* KEYPAD_OUT7 (IOCFG155) */
+ >;
+ pinctrl-single,bias-pulldown = <0 2 0 2>;
+ pinctrl-single,bias-pullup = <0 1 0 1>;
+ };
+ board_ps_pins: pinmux_board_ps_pins {
+ pinctrl-single,pins = <
+ 0x000 0 /* PMU_SPI_CLK (IOCFG191) */
+ 0x008 0 /* PMU_SPI_CS_N (IOCFG193) */
+ >;
+ pinctrl-single,drive-strength = <0x30 0xf0>;
+ };
+ uart0_cfg_func: pincfg_uart0_func {
+ pinctrl-single,pins = <
+ 0x208 0 /* UART0_RXD (IOCFG138) */
+ 0x20c 0 /* UART0_TXD (IOCFG139) */
+ >;
+ pinctrl-single,bias-pulldown = <0 2 0 2>;
+ pinctrl-single,bias-pullup = <0 1 0 1>;
+ };
+ uart0_cfg_idle: pincfg_uart0_idle {
+ pinctrl-single,pins = <
+ 0x208 0 /* UART0_RXD (IOCFG138) */
+ 0x20c 0 /* UART0_TXD (IOCFG139) */
+ >;
+ pinctrl-single,bias-pulldown = <2 2 0 2>;
+ pinctrl-single,bias-pullup = <0 1 0 1>;
+ };
+ uart1_cfg_func: pincfg_uart1_func {
+ pinctrl-single,pins = <
+ 0x210 0 /* UART1_CTS (IOCFG140) */
+ 0x214 0 /* UART1_RTS (IOCFG141) */
+ 0x218 0 /* UART1_RXD (IOCFG142) */
+ 0x21c 0 /* UART1_TXD (IOCFG143) */
+ >;
+ pinctrl-single,bias-pulldown = <0 2 0 2>;
+ pinctrl-single,bias-pullup = <0 1 0 1>;
+ };
+ uart1_cfg_idle: pincfg_uart1_idle {
+ pinctrl-single,pins = <
+ 0x210 0 /* UART1_CTS (IOCFG140) */
+ 0x214 0 /* UART1_RTS (IOCFG141) */
+ 0x218 0 /* UART1_RXD (IOCFG142) */
+ 0x21c 0 /* UART1_TXD (IOCFG143) */
+ >;
+ pinctrl-single,bias-pulldown = <2 2 0 2>;
+ pinctrl-single,bias-pullup = <0 1 0 1>;
+ };
+ uart2_cfg_func: pincfg_uart2_func {
+ pinctrl-single,pins = <
+ 0x220 0 /* UART2_CTS (IOCFG144) */
+ 0x224 0 /* UART2_RTS (IOCFG145) */
+ 0x228 0 /* UART2_RXD (IOCFG146) */
+ 0x22c 0 /* UART2_TXD (IOCFG147) */
+ >;
+ pinctrl-single,bias-pulldown = <0 2 0 2>;
+ pinctrl-single,bias-pullup = <0 1 0 1>;
+ };
+ uart2_cfg_idle: pincfg_uart2_idle {
+ pinctrl-single,pins = <
+ 0x220 0 /* GPIO (IOCFG144) */
+ 0x224 0 /* GPIO (IOCFG145) */
+ 0x228 0 /* GPIO (IOCFG146) */
+ 0x22c 0 /* GPIO (IOCFG147) */
+ >;
+ pinctrl-single,bias-pulldown = <2 2 0 2>;
+ pinctrl-single,bias-pullup = <0 1 0 1>;
+ };
+ uart3_cfg_func: pincfg_uart3_func {
+ pinctrl-single,pins = <
+ 0x294 0 /* UART3_CTS (IOCFG173) */
+ 0x298 0 /* UART3_RTS (IOCFG174) */
+ 0x29c 0 /* UART3_RXD (IOCFG175) */
+ 0x2a0 0 /* UART3_TXD (IOCFG176) */
+ >;
+ pinctrl-single,bias-pulldown = <0 2 0 2>;
+ pinctrl-single,bias-pullup = <0 1 0 1>;
+ };
+ uart3_cfg_idle: pincfg_uart3_idle {
+ pinctrl-single,pins = <
+ 0x294 0 /* UART3_CTS (IOCFG173) */
+ 0x298 0 /* UART3_RTS (IOCFG174) */
+ 0x29c 0 /* UART3_RXD (IOCFG175) */
+ 0x2a0 0 /* UART3_TXD (IOCFG176) */
+ >;
+ pinctrl-single,bias-pulldown = <2 2 0 2>;
+ pinctrl-single,bias-pullup = <0 1 0 1>;
+ };
+ uart4_cfg_func: pincfg_uart4_func {
+ pinctrl-single,pins = <
+ 0x2a4 0 /* UART4_CTS (IOCFG177) */
+ 0x2a8 0 /* UART4_RTS (IOCFG178) */
+ 0x2ac 0 /* UART4_RXD (IOCFG179) */
+ 0x2b0 0 /* UART4_TXD (IOCFG180) */
+ >;
+ pinctrl-single,bias-pulldown = <0 2 0 2>;
+ pinctrl-single,bias-pullup = <0 1 0 1>;
+ };
+ i2c0_cfg_func: pincfg_i2c0_func {
+ pinctrl-single,pins = <
+ 0x17c 0 /* I2C0_SCL (IOCFG103) */
+ 0x180 0 /* I2C0_SDA (IOCFG104) */
+ >;
+ pinctrl-single,bias-pulldown = <0 2 0 2>;
+ pinctrl-single,bias-pullup = <0 1 0 1>;
+ pinctrl-single,drive-strength = <0x30 0xf0>;
+ };
+ i2c1_cfg_func: pincfg_i2c1_func {
+ pinctrl-single,pins = <
+ 0x184 0 /* I2C1_SCL (IOCFG105) */
+ 0x188 0 /* I2C1_SDA (IOCFG106) */
+ >;
+ pinctrl-single,bias-pulldown = <0 2 0 2>;
+ pinctrl-single,bias-pullup = <0 1 0 1>;
+ pinctrl-single,drive-strength = <0x30 0xf0>;
+ };
+ i2c2_cfg_func: pincfg_i2c2_func {
+ pinctrl-single,pins = <
+ 0x118 0 /* I2C2_SCL (IOCFG79) */
+ 0x11c 0 /* I2C2_SDA (IOCFG80) */
+ >;
+ pinctrl-single,bias-pulldown = <0 2 0 2>;
+ pinctrl-single,bias-pullup = <0 1 0 1>;
+ pinctrl-single,drive-strength = <0x30 0xf0>;
+ };
+ i2c3_cfg_func: pincfg_i2c3_func {
+ pinctrl-single,pins = <
+ 0x100 0 /* I2C3_SCL (IOCFG73) */
+ 0x104 0 /* I2C3_SDA (IOCFG74) */
+ >;
+ pinctrl-single,bias-pulldown = <0 2 0 2>;
+ pinctrl-single,bias-pullup = <0 1 0 1>;
+ pinctrl-single,drive-strength = <0x30 0xf0>;
+ };
+ spi0_cfg_func1: pincfg_spi0_f1 {
+ pinctrl-single,pins = <
+ 0x1d4 0 /* SPI0_CLK (IOCFG125) */
+ 0x1d8 0 /* SPI0_DI (IOCFG126) */
+ 0x1dc 0 /* SPI0_DO (IOCFG127) */
+ >;
+ pinctrl-single,bias-pulldown = <2 2 0 2>;
+ pinctrl-single,bias-pullup = <0 1 0 1>;
+ pinctrl-single,drive-strength = <0x30 0xf0>;
+ };
+ spi0_cfg_func2: pincfg_spi0_f2 {
+ pinctrl-single,pins = <
+ 0x1e0 0 /* SPI0_CS0 (IOCFG128) */
+ 0x1e4 0 /* SPI0_CS1 (IOCFG129) */
+ 0x1e8 0 /* SPI0_CS2 (IOCFG130 */
+ 0x1ec 0 /* SPI0_CS3 (IOCFG131) */
+ >;
+ pinctrl-single,bias-pulldown = <0 2 0 2>;
+ pinctrl-single,bias-pullup = <1 1 0 1>;
+ pinctrl-single,drive-strength = <0x30 0xf0>;
+ };
+ spi1_cfg_func1: pincfg_spi1_f1 {
+ pinctrl-single,pins = <
+ 0x1f0 0 /* SPI1_CLK (IOCFG132) */
+ 0x1f4 0 /* SPI1_DI (IOCFG133) */
+ 0x1f8 0 /* SPI1_DO (IOCFG134) */
+ >;
+ pinctrl-single,bias-pulldown = <2 2 0 2>;
+ pinctrl-single,bias-pullup = <0 1 0 1>;
+ pinctrl-single,drive-strength = <0x30 0xf0>;
+ };
+ spi1_cfg_func2: pincfg_spi1_f2 {
+ pinctrl-single,pins = <
+ 0x1fc 0 /* SPI1_CS (IOCFG135) */
+ >;
+ pinctrl-single,bias-pulldown = <0 2 0 2>;
+ pinctrl-single,bias-pullup = <1 1 0 1>;
+ pinctrl-single,drive-strength = <0x30 0xf0>;
+ };
+ kpc_cfg_func: pincfg_kpc_func {
+ pinctrl-single,pins = <
+ 0x250 0 /* KEY_IN0 (IOCFG156) */
+ 0x254 0 /* KEY_IN1 (IOCFG157) */
+ 0x258 0 /* KEY_IN2 (IOCFG158) */
+ 0x230 0 /* KEY_OUT0 (IOCFG148) */
+ 0x234 0 /* KEY_OUT1 (IOCFG149) */
+ 0x238 0 /* KEY_OUT2 (IOCFG150) */
+ >;
+ pinctrl-single,bias-pulldown = <2 2 0 2>;
+ pinctrl-single,bias-pullup = <0 1 0 1>;
+ };
+ emmc_cfg_func: pincfg_emmc_func {
+ pinctrl-single,pins = <
+ 0x0ac 0 /* eMMC_CMD (IOCFG40) */
+ 0x08c 0 /* NAND_DATA8 (IOCFG32) */
+ 0x090 0 /* NAND_DATA9 (IOCFG33) */
+ 0x094 0 /* NAND_DATA10 (IOCFG34) */
+ 0x098 0 /* NAND_DATA11 (IOCFG35) */
+ 0x09c 0 /* NAND_DATA12 (IOCFG36) */
+ 0x0a0 0 /* NAND_DATA13 (IOCFG37) */
+ 0x0a4 0 /* NAND_DATA14 (IOCFG38) */
+ 0x0a8 0 /* NAND_DATA15 (IOCFG39) */
+ >;
+ pinctrl-single,bias-pulldown = <0 2 0 2>;
+ pinctrl-single,bias-pullup = <1 1 0 1>;
+ pinctrl-single,drive-strength = <0x30 0xf0>;
+ };
+ emmc_cfg_clk_func: pincfg_emmc_clk_func {
+ pinctrl-single,pins = <
+ 0x0b0 0 /* eMMC_CLK (IOCFG41) */
+ >;
+ pinctrl-single,bias-pulldown = <0 2 0 2>;
+ pinctrl-single,bias-pullup = <0 1 0 1>;
+ pinctrl-single,drive-strength = <0x30 0xf0>;
+ };
+ sd_cfg_func1: pincfg_sd_f1 {
+ pinctrl-single,pins = <
+ 0x18c 0 /* SD_CLK (IOCFG107) */
+ >;
+ pinctrl-single,bias-pulldown = <0 2 0 2>;
+ pinctrl-single,bias-pullup = <0 1 0 1>;
+ pinctrl-single,drive-strength = <0x30 0xf0>;
+ };
+ sd_cfg_func2: pincfg_sd_f2 {
+ pinctrl-single,pins = <
+ 0x190 0 /* SD_CMD (IOCFG108) */
+ 0x194 0 /* SD_DATA0 (IOCFG109) */
+ 0x198 0 /* SD_DATA1 (IOCFG110) */
+ 0x19c 0 /* SD_DATA2 (IOCFG111) */
+ 0x1a0 0 /* SD_DATA3 (IOCFG112) */
+ >;
+ pinctrl-single,bias-pulldown = <0 2 0 2>;
+ pinctrl-single,bias-pullup = <1 1 0 1>;
+ pinctrl-single,drive-strength = <0x70 0xf0>;
+ };
+ nand_cfg_func1: pincfg_nand_f1 {
+ pinctrl-single,pins = <
+ 0x03c 0 /* NAND_ALE (IOCFG12) */
+ 0x040 0 /* NAND_CLE (IOCFG13) */
+ 0x06c 0 /* NAND_DATA0 (IOCFG24) */
+ 0x070 0 /* NAND_DATA1 (IOCFG25) */
+ 0x074 0 /* NAND_DATA2 (IOCFG26) */
+ 0x078 0 /* NAND_DATA3 (IOCFG27) */
+ 0x07c 0 /* NAND_DATA4 (IOCFG28) */
+ 0x080 0 /* NAND_DATA5 (IOCFG29) */
+ 0x084 0 /* NAND_DATA6 (IOCFG30) */
+ 0x088 0 /* NAND_DATA7 (IOCFG31) */
+ 0x08c 0 /* NAND_DATA8 (IOCFG32) */
+ 0x090 0 /* NAND_DATA9 (IOCFG33) */
+ 0x094 0 /* NAND_DATA10 (IOCFG34) */
+ 0x098 0 /* NAND_DATA11 (IOCFG35) */
+ 0x09c 0 /* NAND_DATA12 (IOCFG36) */
+ 0x0a0 0 /* NAND_DATA13 (IOCFG37) */
+ 0x0a4 0 /* NAND_DATA14 (IOCFG38) */
+ 0x0a8 0 /* NAND_DATA15 (IOCFG39) */
+ >;
+ pinctrl-single,bias-pulldown = <2 2 0 2>;
+ pinctrl-single,bias-pullup = <0 1 0 1>;
+ pinctrl-single,drive-strength = <0x30 0xf0>;
+ };
+ nand_cfg_func2: pincfg_nand_f2 {
+ pinctrl-single,pins = <
+ 0x044 0 /* NAND_RE_N (IOCFG14) */
+ 0x048 0 /* NAND_WE_N (IOCFG15) */
+ 0x04c 0 /* NAND_CS0_N (IOCFG16) */
+ 0x050 0 /* NAND_CS1_N (IOCFG17) */
+ 0x054 0 /* NAND_CS2_N (IOCFG18) */
+ 0x058 0 /* NAND_CS3_N (IOCFG19) */
+ 0x05c 0 /* NAND_BUSY0_N (IOCFG20) */
+ 0x060 0 /* NAND_BUSY1_N (IOCFG21) */
+ 0x064 0 /* NAND_BUSY2_N (IOCFG22) */
+ 0x068 0 /* NAND_BUSY3_N (IOCFG23) */
+ >;
+ pinctrl-single,bias-pulldown = <0 2 0 2>;
+ pinctrl-single,bias-pullup = <1 1 0 1>;
+ pinctrl-single,drive-strength = <0x30 0xf0>;
+ };
+ sdio_cfg_func: pincfg_sdio_func {
+ pinctrl-single,pins = <
+ 0x1a4 0 /* SDIO0_CLK (IOCG113) */
+ 0x1a8 0 /* SDIO0_CMD (IOCG114) */
+ 0x1ac 0 /* SDIO0_DATA0 (IOCG115) */
+ 0x1b0 0 /* SDIO0_DATA1 (IOCG116) */
+ 0x1b4 0 /* SDIO0_DATA2 (IOCG117) */
+ 0x1b8 0 /* SDIO0_DATA3 (IOCG118) */
+ >;
+ pinctrl-single,bias-pulldown = <2 2 0 2>;
+ pinctrl-single,bias-pullup = <0 1 0 1>;
+ pinctrl-single,drive-strength = <0x30 0xf0>;
+ };
+ audio_out_cfg_func: pincfg_audio_func {
+ pinctrl-single,pins = <
+ 0x200 0 /* GPIO (IOCFG136) */
+ 0x204 0 /* GPIO (IOCFG137) */
+ >;
+ pinctrl-single,bias-pulldown = <2 2 0 2>;
+ pinctrl-single,bias-pullup = <0 1 0 1>;
+ };
+ pmic_int_cfg_func: pincfg_pmic_func {
+ pinctrl-single,pins = <
+ 0x018 0 /* GPIO159 (IOCFG003) */
+ >;
+ };
+ /* TP_IRQ need pullup */
+ ts_pin_cfg: pincfg_ts_func {
+ pinctrl-single,pins = <
+ 0x010 0 /* GPIO157 (TP_IRQ) */
+ >;
+ pinctrl-single,bias-pulldown = <0 2 0 2>;
+ pinctrl-single,bias-pullup = <1 1 0 1>;
+ };
+ pwm0_cfg_func: pincfg_pwm0_func {
+ pinctrl-single,pins = <
+ 0x280 0 /* PWM0 (IOCFG168) */
+ >;
+ pinctrl-single,bias-pulldown = <2 2 0 2>;
+ pinctrl-single,bias-pullup = <0 1 0 1>;
+ pinctrl-single,drive-strength = <0x30 0xf0>;
+ };
+ pwm1_cfg_func: pincfg_pwm1_func {
+ pinctrl-single,pins = <
+ 0x284 0 /* PWM1 (IOCFG169) */
+ >;
+ pinctrl-single,bias-pulldown = <2 2 0 2>;
+ pinctrl-single,bias-pullup = <0 1 0 1>;
+ pinctrl-single,drive-strength = <0x30 0xf0>;
+ };
+ pmic_int_cfg_func: pincfg_pmic_func {
+ pinctrl-single,pins = <
+ 0x018 0 /* GPIO159 (IOCFG003) */
+ >;
+ };
+ };
+
+ i2c0: i2c@fcb08000 {
+ status = "ok";
+ pinctrl-names = "default", "idle";
+ pinctrl-0 = <&i2c0_pmx_func &i2c0_cfg_func>;
+ pinctrl-1 = <&i2c0_pmx_idle &i2c0_cfg_func>;
+ };
+
+ i2c1: i2c@fcb09000 {
+ status = "ok";
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pmx_func &i2c1_cfg_func>;
+ ts_mxt224e: ts@4a {
+ compatible = "atmel,ts-mxt224e";
+ reg = <0x4a>;
+ ldo-supply = <&ldo6>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&ts_pin_cfg>;
+ atmel-ts,gpio-irq = <&gpio19 5 0>;
+ atmel-ts,gpio-reset = <&gpio19 4 0>;
+ /* min max: x y pressure width */
+ atmel-ts,abs = <0 719 0 1279 0 255 0 255>;
+ atmel-ts,cfg_t6 = /bits/ 8 <0 0 0 0 0 0>;
+ atmel-ts,cfg_t7 = /bits/ 8 <32 255 10>;
+ atmel-ts,cfg_t8 = /bits/ 8 <24 0 1 10 0 0 5 60 10 192>;
+ atmel-ts,cfg_t9 = /bits/ 8 <143 0 0 19 11 0 32 66 2 3 0 2 2 47 10 15 22 10 106 5
+ 207 2 0 0 0 0 161 40 183 64 30 20 0 0 1>;
+ atmel-ts,cfg_t15 = /bits/ 8 <0 0 0 0 0 0 0 0 0 0 0>;
+ atmel-ts,cfg_t19 = /bits/ 8 <0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0>;
+ atmel-ts,cfg_t23 = /bits/ 8 <0 0 0 0 0 0 0 0 0 0 0 0 0 0 0>;
+ atmel-ts,cfg_t25 = /bits/ 8 <0 0 0 0 0 0 0 0 0 0 0 0 0 0>;
+ atmel-ts,cfg_t40 = /bits/ 8 <0 0 0 0 0>;
+ atmel-ts,cfg_t42 = /bits/ 8 <0 40 40 80 128 0 0 0>;
+ atmel-ts,cfg_t46 = /bits/ 8 <0 3 32 32 0 0 0 0 0>;
+ atmel-ts,cfg_t47 = /bits/ 8 <0 20 50 5 2 40 40 180 0 100>;
+ atmel-ts,cfg_t48 = /bits/ 8 <1 4 10 0 0 0 0 0 1 1 0 0 0 6 6 0 0 63 6 64
+ 10 0 20 5 0 38 0 20 0 0 0 0 0 0 0 40 2 2 2 32
+ 10 12 20 241 251 0 0 191 40 183 64 30 15 0>;
+ atmel-ts,object_crc = /bits/ 8 <0xFD 0x3B 0x8D>;
+ atmel-ts,cable_config = /bits/ 8 <70 30 32 32>;
+ atmel-ts,cable_config_t7 = /bits/ 8 <32 16 25>;
+ atmel-ts,cable_config_t8 = /bits/ 8 <24 0 5 5 0 0 5 60 10 192>;
+ atmel-ts,cable_config_T9 = /bits/ 8 <139 0 0 19 11 0 32 66 2 3 0 5 2 64 10
+ 12 20 10 106 5 207 2 0 0 0 0 161 40 183 64 30 20 0 0 0>;
+ atmel-ts,cable_config_t46 = /bits/ 8 <0 3 40 40 0 0 0 0 0>;
+ atmel-ts,cable_config_t48 = /bits/ 8 <1 128 114 0 0 0 0 0 1 2 0 0 0 6 6
+ 0 0 63 6 64 10 0 20 5 0 38 0 20 0 0 0 0 0 0 0
+ 40 2 2 2 32 10 12 20 241 251 0 0 191 40 183 64 30 15 0>;
+ atmel-ts,noise_config = /bits/ 8 <70 3 35>;
+ atmel-ts,filter_level = /bits/ 16 <0 0 539 539>;
+ atmel-ts,gcaf_level = /bits/ 8 <8 16 24 32 40>;
+ atmel-ts,atch_nor = /bits/ 8 <0 0 5 60 10 192>;
+ atmel-ts,atch_nor_20s = /bits/ 8 <0 0 255 1 0 0>;
+ };
+ };
+
+ dwmmc1@fcd04000 {
+ num-slots = <1>;
+ vmmc-supply = <&ldo0>;
+ vqmmc-supply = <&ldo5>;
+ /* emmc fifo register value is incorrect */
+ fifo-depth = <0x100>;
+ broken-cd;
+ supports-highspeed;
+ pinctrl-names = "default";
+ pinctrl-0 = <&emmc_pmx_func &emmc_cfg_func &emmc_cfg_clk_func>;
+ slot@0 {
+ reg = <0>;
+ bus-width = <8>;
+ disable-wp;
+ };
+ };
+
+ dwmmc0@fcd03000 {
+ num-slots = <1>;
+ vmmc-supply = <&ldo12>;
+ fifo-depth = <0x100>;
+ supports-highspeed;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sd_pmx_pins &sd_cfg_func1 &sd_cfg_func2>;
+ cd-gpio = <&gpio10 3 0>;
+ slot@0 {
+ reg = <0>;
+ bus-width = <4>;
+ disable-wp;
+ };
+ };
+
+ dwmmc2@fcd05000 {
+ status = "disabled";
+ };
+
+ dwmmc3@fcd06000 {
+ status = "disabled";
+ };
+
+ power_management {
+ compatible = "hisilicon,hs-power-management";
+ reg = <0xfcc00000 0x0240>, /* pmu_spi_base_addr */
+ <0xf8000000 0x14000>, /* secram_base_addr */
+ <0xfca09000 0x1000>, /* pctrl_base_addr */
+ <0xfc000000 0x2000>, /* a9_per_base_addr */
+ <0xfcb00000 0x1000>, /* uart0_base_addr, console workaround */
+ <0xfc803000 0x1000>; /* io_base, console workaround */
+ pmu-power-hold-gpios = <&gpio19 6 0>;
+ };
+
+ edc0: edc@fa202000 {
+ hisilicon,pixel-format = "RGB565";
+ hisilicon,color-mode = <5>;
+ hisilicon,dsi-clock-frequency = <270000000>; /* 241MHz, not 300MHz */
+ hisilicon,mipi-mode = "video";
+ hisilicon,mipi-lanes = <4>;
+ status = "ok";
+
+ display-timings {
+ native-mode = <&timing0>;
+ timing0: timing0 {
+ clock-frequency = <68000000>; /* 13.158MHz pixel clock */
+ hactive = <720>;
+ vactive = <1280>;
+ hsync-active = <0>;
+ vsync-active = <0>;
+ de-active = <1>;
+ pixelclk-active = <1>;
+ hfront-porch = <96>;
+ hback-porch = <16>;
+ hsync-len = <16>;
+ vfront-porch = <12>;
+ vback-porch = <12>;
+ vsync-len = <16>;
+ };
+ };
+ };
+
+ pmic: pmic@fcc00000 {
+ compatible = "hisilicon,hi6421-pmic";
+ reg = <0xfcc00000 0x0180>; /* 0x60 << 2 */
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ gpios = <&gpio19 7 0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pmic_int_cfg_func>;
+
+ ldo0: ldo@20 {
+ compatible = "hisilicon,hi6421-ldo";
+ regulator-name = "LDO0";
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <2850000>;
+ hisilicon,hi6421-ctrl = <0x20 0x10 0x20>;
+ hisilicon,hi6421-vset = <0x20 0x07>;
+ hisilicon,hi6421-n-voltages = <8>;
+ hisilicon,hi6421-vset-table = <1500000>, <1800000>,
+ <2400000>, <2500000>,
+ <2600000>, <2700000>,
+ <2850000>, <3000000>;
+ hisilicon,hi6421-off-on-delay-us = <10000>;
+ hisilicon,hi6421-enable-time-us = <250>;
+ hisilicon,hi6421-eco-microamp = <8000>;
+ };
+
+ ldo1: ldo@21 {
+ compatible = "hisilicon,hi6421-ldo";
+ regulator-name = "LDO1";
+ regulator-min-microvolt = <1700000>;
+ regulator-max-microvolt = <2000000>;
+ regulator-boot-on;
+ regulator-always-on;
+ hisilicon,hi6421-ctrl = <0x21 0x10 0x20>;
+ hisilicon,hi6421-vset = <0x21 0x03>;
+ hisilicon,hi6421-n-voltages = <4>;
+ hisilicon,hi6421-vset-table = <1700000>, <1800000>,
+ <1900000>, <2000000>;
+ hisilicon,hi6421-off-on-delay-us = <10000>;
+ hisilicon,hi6421-enable-time-us = <250>;
+ hisilicon,hi6421-eco-microamp = <5000>;
+ };
+
+ ldo2: ldo@22 {
+ compatible = "hisilicon,hi6421-ldo";
+ regulator-name = "LDO2";
+ regulator-min-microvolt = <1050000>;
+ regulator-max-microvolt = <1400000>;
+ regulator-boot-on;
+ regulator-always-on;
+ hisilicon,hi6421-ctrl = <0x22 0x10 0x20>;
+ hisilicon,hi6421-vset = <0x22 0x07>;
+ hisilicon,hi6421-n-voltages = <8>;
+ hisilicon,hi6421-vset-table = <1050000>, <1100000>,
+ <1150000>, <1200000>,
+ <1250000>, <1300000>,
+ <1350000>, <1400000>;
+ hisilicon,hi6421-off-on-delay-us = <20000>;
+ hisilicon,hi6421-enable-time-us = <250>;
+ hisilicon,hi6421-eco-microamp = <8000>;
+ };
+
+ ldo3: ldo@23 {
+ compatible = "hisilicon,hi6421-ldo";
+ regulator-name = "LDO3";
+ regulator-min-microvolt = <1050000>;
+ regulator-max-microvolt = <1400000>;
+ regulator-boot-on;
+ regulator-always-on;
+ hisilicon,hi6421-ctrl = <0x23 0x10 0x20>;
+ hisilicon,hi6421-vset = <0x23 0x07>;
+ hisilicon,hi6421-n-voltages = <8>;
+ hisilicon,hi6421-vset-table = <1050000>, <1100000>,
+ <1150000>, <1200000>,
+ <1250000>, <1300000>,
+ <1350000>, <1400000>;
+ hisilicon,hi6421-off-on-delay-us = <20000>;
+ hisilicon,hi6421-enable-time-us = <250>;
+ hisilicon,hi6421-eco-microamp = <8000>;
+ };
+
+ ldo4: ldo@24 {
+ compatible = "hisilicon,hi6421-ldo";
+ regulator-name = "LDO4";
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-boot-on;
+ regulator-always-on;
+ hisilicon,hi6421-ctrl = <0x24 0x10 0x20>;
+ hisilicon,hi6421-vset = <0x24 0x07>;
+ hisilicon,hi6421-n-voltages = <8>;
+ hisilicon,hi6421-vset-table = <1500000>, <1800000>,
+ <2400000>, <2500000>,
+ <2600000>, <2700000>,
+ <2850000>, <3000000>;
+ hisilicon,hi6421-off-on-delay-us = <20000>;
+ hisilicon,hi6421-enable-time-us = <250>;
+ hisilicon,hi6421-eco-microamp = <8000>;
+ };
+
+ ldo5: ldo@25 {
+ compatible = "hisilicon,hi6421-ldo";
+ regulator-name = "LDO5";
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-boot-on;
+ regulator-always-on;
+ hisilicon,hi6421-ctrl = <0x25 0x10 0x20>;
+ hisilicon,hi6421-vset = <0x25 0x07>;
+ hisilicon,hi6421-n-voltages = <8>;
+ hisilicon,hi6421-vset-table = <1500000>, <1800000>,
+ <2400000>, <2500000>,
+ <2600000>, <2700000>,
+ <2850000>, <3000000>;
+ hisilicon,hi6421-off-on-delay-us = <20000>;
+ hisilicon,hi6421-enable-time-us = <250>;
+ hisilicon,hi6421-eco-microamp = <8000>;
+ };
+
+ ldo6: ldo@26 {
+ compatible = "hisilicon,hi6421-ldo";
+ regulator-name = "LDO6";
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-boot-on;
+ regulator-always-on;
+ hisilicon,hi6421-ctrl = <0x26 0x10 0x20>;
+ hisilicon,hi6421-vset = <0x26 0x07>;
+ hisilicon,hi6421-n-voltages = <8>;
+ hisilicon,hi6421-vset-table = <1500000>, <1800000>,
+ <2400000>, <2500000>,
+ <2600000>, <2700000>,
+ <2850000>, <3000000>;
+ hisilicon,hi6421-off-on-delay-us = <20000>;
+ hisilicon,hi6421-enable-time-us = <250>;
+ hisilicon,hi6421-eco-microamp = <8000>;
+ };
+
+ ldo7: ldo@27 {
+ compatible = "hisilicon,hi6421-ldo";
+ regulator-name = "LDO7";
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-boot-on;
+ regulator-always-on;
+ hisilicon,hi6421-ctrl = <0x27 0x10 0x20>;
+ hisilicon,hi6421-vset = <0x27 0x07>;
+ hisilicon,hi6421-n-voltages = <8>;
+ hisilicon,hi6421-vset-table = <1500000>, <1800000>,
+ <2400000>, <2500000>,
+ <2600000>, <2700000>,
+ <2850000>, <3000000>;
+ hisilicon,hi6421-off-on-delay-us = <20000>;
+ hisilicon,hi6421-enable-time-us = <250>;
+ hisilicon,hi6421-eco-microamp = <5000>;
+ };
+
+ ldo8: ldo@28 {
+ compatible = "hisilicon,hi6421-ldo";
+ regulator-name = "LDO8";
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ regulator-always-on;
+ hisilicon,hi6421-ctrl = <0x28 0x10 0x20>;
+ hisilicon,hi6421-vset = <0x28 0x07>;
+ hisilicon,hi6421-n-voltages = <8>;
+ hisilicon,hi6421-vset-table = <1500000>, <1800000>,
+ <2400000>, <2600000>,
+ <2700000>, <2850000>,
+ <3000000>, <3300000>;
+ hisilicon,hi6421-off-on-delay-us = <20000>;
+ hisilicon,hi6421-enable-time-us = <250>;
+ hisilicon,hi6421-eco-microamp = <8000>;
+ };
+
+ ldo9: ldo@29 {
+ compatible = "hisilicon,hi6421-ldo";
+ regulator-name = "LDO9";
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <3000000>;
+ hisilicon,hi6421-ctrl = <0x29 0x10 0x20>;
+ hisilicon,hi6421-vset = <0x29 0x07>;
+ hisilicon,hi6421-n-voltages = <8>;
+ hisilicon,hi6421-vset-table = <1500000>, <1800000>,
+ <2400000>, <2500000>,
+ <2600000>, <2700000>,
+ <2850000>, <3000000>;
+ hisilicon,hi6421-off-on-delay-us = <40000>;
+ hisilicon,hi6421-enable-time-us = <250>;
+ hisilicon,hi6421-eco-microamp = <8000>;
+ };
+
+ ldo10: ldo@2a {
+ compatible = "hisilicon,hi6421-ldo";
+ regulator-name = "LDO10";
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <3000000>;
+ hisilicon,hi6421-ctrl = <0x2a 0x10 0x20>;
+ hisilicon,hi6421-vset = <0x2a 0x07>;
+ hisilicon,hi6421-n-voltages = <8>;
+ hisilicon,hi6421-vset-table = <1500000>, <1800000>,
+ <2400000>, <2500000>,
+ <2600000>, <2700000>,
+ <2850000>, <3000000>;
+ hisilicon,hi6421-off-on-delay-us = <40000>;
+ hisilicon,hi6421-enable-time-us = <250>;
+ hisilicon,hi6421-eco-microamp = <8000>;
+ };
+
+ ldo11: ldo@2b {
+ compatible = "hisilicon,hi6421-ldo";
+ regulator-name = "LDO11";
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <3000000>;
+ hisilicon,hi6421-ctrl = <0x2b 0x10 0x20>;
+ hisilicon,hi6421-vset = <0x2b 0x07>;
+ hisilicon,hi6421-n-voltages = <8>;
+ hisilicon,hi6421-vset-table = <1500000>, <1800000>,
+ <2400000>, <2500000>,
+ <2600000>, <2700000>,
+ <2850000>, <3000000>;
+ hisilicon,hi6421-off-on-delay-us = <40000>;
+ hisilicon,hi6421-enable-time-us = <250>;
+ hisilicon,hi6421-eco-microamp = <8000>;
+ };
+
+ ldo12: ldo@2c {
+ compatible = "hisilicon,hi6421-ldo";
+ regulator-name = "LDO12";
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <2850000>;
+ hisilicon,hi6421-ctrl = <0x2c 0x10 0x20>;
+ hisilicon,hi6421-vset = <0x2c 0x07>;
+ hisilicon,hi6421-n-voltages = <8>;
+ hisilicon,hi6421-vset-table = <1500000>, <1800000>,
+ <2400000>, <2500000>,
+ <2600000>, <2700000>,
+ <2850000>, <3000000>;
+ hisilicon,hi6421-off-on-delay-us = <40000>;
+ hisilicon,hi6421-enable-time-us = <250>;
+ hisilicon,hi6421-eco-microamp = <8000>;
+ };
+
+ ldo13: ldo@2d {
+ compatible = "hisilicon,hi6421-ldo";
+ regulator-name = "LDO13";
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <3000000>;
+ hisilicon,hi6421-ctrl = <0x2d 0x10 0x20>;
+ hisilicon,hi6421-vset = <0x2d 0x07>;
+ hisilicon,hi6421-n-voltages = <8>;
+ hisilicon,hi6421-vset-table = <1500000>, <1800000>,
+ <2400000>, <2500000>,
+ <2600000>, <2700000>,
+ <2850000>, <3000000>;
+ hisilicon,hi6421-off-on-delay-us = <40000>;
+ hisilicon,hi6421-enable-time-us = <250>;
+ hisilicon,hi6421-eco-microamp = <8000>;
+ };
+
+ ldo14: ldo@2e {
+ compatible = "hisilicon,hi6421-ldo";
+ regulator-name = "LDO14";
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <3000000>;
+ hisilicon,hi6421-ctrl = <0x2e 0x10 0x20>;
+ hisilicon,hi6421-vset = <0x2e 0x07>;
+ hisilicon,hi6421-n-voltages = <8>;
+ hisilicon,hi6421-vset-table = <1500000>, <1800000>,
+ <2400000>, <2500000>,
+ <2600000>, <2700000>,
+ <2850000>, <3000000>;
+ hisilicon,hi6421-off-on-delay-us = <40000>;
+ hisilicon,hi6421-enable-time-us = <250>;
+ hisilicon,hi6421-eco-microamp = <8000>;
+ };
+
+ ldo15: ldo@2f {
+ compatible = "hisilicon,hi6421-ldo";
+ regulator-name = "LDO15";
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <3300000>;
+ hisilicon,hi6421-ctrl = <0x2f 0x10 0x20>;
+ hisilicon,hi6421-vset = <0x2f 0x07>;
+ hisilicon,hi6421-n-voltages = <8>;
+ hisilicon,hi6421-vset-table = <1500000>, <1800000>,
+ <2400000>, <2600000>,
+ <2700000>, <2850000>,
+ <3000000>, <3300000>;
+ hisilicon,hi6421-off-on-delay-us = <40000>;
+ hisilicon,hi6421-enable-time-us = <250>;
+ hisilicon,hi6421-eco-microamp = <8000>;
+ };
+
+ ldo16: ldo@30 {
+ compatible = "hisilicon,hi6421-ldo";
+ regulator-name = "LDO16";
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-always-on;
+ hisilicon,hi6421-ctrl = <0x30 0x10 0x20>;
+ hisilicon,hi6421-vset = <0x30 0x07>;
+ hisilicon,hi6421-n-voltages = <8>;
+ hisilicon,hi6421-vset-table = <1500000>, <1800000>,
+ <2400000>, <2500000>,
+ <2600000>, <2700000>,
+ <2850000>, <3000000>;
+ hisilicon,hi6421-off-on-delay-us = <40000>;
+ hisilicon,hi6421-enable-time-us = <250>;
+ hisilicon,hi6421-eco-microamp = <8000>;
+ };
+
+ ldo17: ldo@31 {
+ compatible = "hisilicon,hi6421-ldo";
+ regulator-name = "LDO17";
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-always-on;
+ hisilicon,hi6421-ctrl = <0x31 0x10 0x20>;
+ hisilicon,hi6421-vset = <0x31 0x07>;
+ hisilicon,hi6421-n-voltages = <8>;
+ hisilicon,hi6421-vset-table = <1500000>, <1800000>,
+ <2400000>, <2500000>,
+ <2600000>, <2700000>,
+ <2850000>, <3000000>;
+ hisilicon,hi6421-off-on-delay-us = <40000>;
+ hisilicon,hi6421-enable-time-us = <250>;
+ hisilicon,hi6421-eco-microamp = <8000>;
+ };
+
+ ldo18: ldo@32 {
+ compatible = "hisilicon,hi6421-ldo";
+ regulator-name = "LDO18";
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <3000000>;
+ hisilicon,hi6421-ctrl = <0x32 0x10 0x20>;
+ hisilicon,hi6421-vset = <0x32 0x07>;
+ hisilicon,hi6421-n-voltages = <8>;
+ hisilicon,hi6421-vset-table = <1500000>, <1800000>,
+ <2400000>, <2500000>,
+ <2600000>, <2700000>,
+ <2850000>, <3000000>;
+ hisilicon,hi6421-off-on-delay-us = <40000>;
+ hisilicon,hi6421-enable-time-us = <250>;
+ hisilicon,hi6421-eco-microamp = <8000>;
+ };
+
+ ldo19: ldo@33 {
+ compatible = "hisilicon,hi6421-ldo";
+ regulator-name = "LDO19";
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <3000000>;
+ hisilicon,hi6421-ctrl = <0x2a 0x10 0x20>;
+ hisilicon,hi6421-vset = <0x2a 0x07>;
+ hisilicon,hi6421-n-voltages = <8>;
+ hisilicon,hi6421-vset-table = <1500000>, <1800000>,
+ <2400000>, <2500000>,
+ <2600000>, <2700000>,
+ <2850000>, <3000000>;
+ hisilicon,hi6421-off-on-delay-us = <40000>;
+ hisilicon,hi6421-enable-time-us = <250>;
+ hisilicon,hi6421-eco-microamp = <8000>;
+ };
+
+ ldo20: ldo@34 {
+ compatible = "hisilicon,hi6421-ldo";
+ regulator-name = "LDO20";
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <3000000>;
+ hisilicon,hi6421-ctrl = <0x34 0x10 0x20>;
+ hisilicon,hi6421-vset = <0x34 0x07>;
+ hisilicon,hi6421-n-voltages = <8>;
+ hisilicon,hi6421-vset-table = <1500000>, <1800000>,
+ <2400000>, <2500000>,
+ <2600000>, <2700000>,
+ <2850000>, <3000000>;
+ hisilicon,hi6421-off-on-delay-us = <40000>;
+ hisilicon,hi6421-enable-time-us = <250>;
+ hisilicon,hi6421-eco-microamp = <8000>;
+ };
+
+ ldoaudio: ldo@36 {
+ compatible = "hisilicon,hi6421-ldo";
+ regulator-name = "LDOAUDIO";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <3300000>;
+ hisilicon,hi6421-ctrl = <0x36 0x01 0x02>;
+ hisilicon,hi6421-vset = <0x36 0x70>;
+ hisilicon,hi6421-n-voltages = <8>;
+ hisilicon,hi6421-vset-table = <2800000>, <2850000>,
+ <2900000>, <2950000>,
+ <3000000>, <3100000>,
+ <3200000>, <3300000>;
+ hisilicon,hi6421-off-on-delay-us = <40000>;
+ hisilicon,hi6421-enable-time-us = <250>;
+ hisilicon,hi6421-eco-microamp = <5000>;
+ };
+
+ buck0: buck@0c {
+ compatible = "hisilicon,hi6421-buck012";
+ regulator-name = "BUCK0";
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <1600000>;
+ regulator-boot-on;
+ regulator-always-on;
+ hisilicon,hi6421-ctrl = <0x0c 0x01 0x10>;
+ hisilicon,hi6421-vset = <0x0d 0x7f>;
+ hisilicon,hi6421-n-voltages = <128>;
+ hisilicon,hi6421-uv-step = <7086>;
+ hisilicon,hi6421-off-on-delay-us = <20000>;
+ hisilicon,hi6421-enable-time-us = <300>;
+ };
+
+ buck1: buck@0e {
+ compatible = "hisilicon,hi6421-buck012";
+ regulator-name = "BUCK1";
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <1600000>;
+ regulator-boot-on;
+ regulator-always-on;
+ hisilicon,hi6421-ctrl = <0x0e 0x01 0x10>;
+ hisilicon,hi6421-vset = <0x0f 0x7f>;
+ hisilicon,hi6421-n-voltages = <128>;
+ hisilicon,hi6421-uv-step = <7086>;
+ hisilicon,hi6421-off-on-delay-us = <20000>;
+ hisilicon,hi6421-enable-time-us = <300>;
+ };
+
+ buck2: buck@10 {
+ compatible = "hisilicon,hi6421-buck012";
+ regulator-name = "BUCK2";
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <1600000>;
+ regulator-boot-on;
+ hisilicon,hi6421-ctrl = <0x10 0x01 0x10>;
+ hisilicon,hi6421-vset = <0x11 0x7f>;
+ hisilicon,hi6421-n-voltages = <128>;
+ hisilicon,hi6421-uv-step = <7086>;
+ hisilicon,hi6421-off-on-delay-us = <100>;
+ hisilicon,hi6421-enable-time-us = <250>;
+ };
+
+ buck3: buck@12 {
+ compatible = "hisilicon,hi6421-buck345";
+ regulator-name = "BUCK3";
+ regulator-min-microvolt = <950000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-boot-on;
+ regulator-always-on;
+ hisilicon,hi6421-ctrl = <0x12 0x01 0x10>;
+ hisilicon,hi6421-vset = <0x13 0x07>;
+ hisilicon,hi6421-n-voltages = <8>;
+ hisilicon,hi6421-vset-table = <950000>, <1050000>,
+ <1100000>, <1170000>,
+ <1134000>, <1150000>,
+ <1167000>, <1200000>;
+ hisilicon,hi6421-off-on-delay-us = <20000>;
+ hisilicon,hi6421-enable-time-us = <250>;
+ };
+
+ buck4: buck@14 {
+ compatible = "hisilicon,hi6421-buck345";
+ regulator-name = "BUCK4";
+ regulator-min-microvolt = <1150000>;
+ regulator-max-microvolt = <2000000>;
+ regulator-boot-on;
+ regulator-always-on;
+ hisilicon,hi6421-ctrl = <0x14 0x01 0x10>;
+ hisilicon,hi6421-vset = <0x15 0x07>;
+ hisilicon,hi6421-n-voltages = <8>;
+ hisilicon,hi6421-vset-table = <1150000>, <1200000>,
+ <1250000>, <1350000>,
+ <1700000>, <1800000>,
+ <1900000>, <2000000>;
+ hisilicon,hi6421-off-on-delay-us = <20000>;
+ hisilicon,hi6421-enable-time-us = <250>;
+ };
+
+ buck5: buck@16 {
+ compatible = "hisilicon,hi6421-buck345";
+ regulator-name = "BUCK5";
+ regulator-min-microvolt = <1150000>;
+ regulator-max-microvolt = <1900000>;
+ regulator-boot-on;
+ regulator-always-on;
+ hisilicon,hi6421-ctrl = <0x16 0x01 0x10>;
+ hisilicon,hi6421-vset = <0x17 0x07>;
+ hisilicon,hi6421-n-voltages = <8>;
+ hisilicon,hi6421-vset-table = <1150000>, <1200000>,
+ <1250000>, <1350000>,
+ <1600000>, <1700000>,
+ <1800000>, <1900000>;
+ hisilicon,hi6421-off-on-delay-us = <20000>;
+ hisilicon,hi6421-enable-time-us = <250>;
+ };
+
+ onkey {
+ compatible = "hisilicon,hi6421-onkey";
+ interrupt-parent = <&pmic>;
+ interrupts = <7 0>, <6 0>, <5 0>, <4 0>;
+ interrupt-names = "down", "up", "hold 1s", "hold 10s";
+ };
+
+ rtc {
+ compatible = "hisilicon,hi6421-rtc";
+ interrupt-parent = <&pmic>;
+ interrupts = <0 0>;
+ };
+ }; /* end of pmic */
+ };
+};
diff --git a/arch/arm/configs/hs_defconfig b/arch/arm/configs/hs_defconfig
new file mode 100644
index 000000000000..bb1e921fb9aa
--- /dev/null
+++ b/arch/arm/configs/hs_defconfig
@@ -0,0 +1,1998 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Linux/arm 3.8.0-rc3 Kernel Configuration
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_HAVE_PROC_CPU=y
+CONFIG_NO_IOPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_ARM_PATCH_PHYS_VIRT=y
+CONFIG_GENERIC_BUG=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_HAVE_IRQ_WORK=y
+CONFIG_BUILDTIME_EXTABLE_SORT=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_CROSS_COMPILE=""
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_XZ=y
+CONFIG_HAVE_KERNEL_LZO=y
+CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_LZMA is not set
+# CONFIG_KERNEL_XZ is not set
+# CONFIG_KERNEL_LZO is not set
+CONFIG_DEFAULT_HOSTNAME="(none)"
+CONFIG_SWAP=y
+# CONFIG_SYSVIPC is not set
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_FHANDLE is not set
+# CONFIG_AUDIT is not set
+CONFIG_HAVE_GENERIC_HARDIRQS=y
+
+#
+# IRQ subsystem
+#
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_CHIP=y
+CONFIG_IRQ_DOMAIN=y
+CONFIG_IRQ_DOMAIN_DEBUG=y
+CONFIG_SPARSE_IRQ=y
+CONFIG_KTIME_SCALAR=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
+
+#
+# Timers subsystem
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+
+#
+# CPU/Task time and stats accounting
+#
+CONFIG_TICK_CPU_ACCOUNTING=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_PREEMPT_RCU is not set
+CONFIG_RCU_FANOUT=32
+CONFIG_RCU_FANOUT_LEAF=16
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_RCU_FAST_NO_HZ is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_RCU_NOCB_CPU is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=17
+# CONFIG_CGROUPS is not set
+# CONFIG_CHECKPOINT_RESTORE is not set
+CONFIG_NAMESPACES=y
+CONFIG_UTS_NS=y
+# CONFIG_USER_NS is not set
+CONFIG_PID_NS=y
+CONFIG_NET_NS=y
+CONFIG_UIDGID_CONVERTED=y
+# CONFIG_UIDGID_STRICT_TYPE_CHECKS is not set
+# CONFIG_SCHED_AUTOGROUP is not set
+# CONFIG_SYSFS_DEPRECATED is not set
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE="/opt/workspace/kernel/rootfs/"
+CONFIG_INITRAMFS_ROOT_UID=0
+CONFIG_INITRAMFS_ROOT_GID=0
+CONFIG_RD_GZIP=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_RD_XZ=y
+CONFIG_RD_LZO=y
+# CONFIG_INITRAMFS_COMPRESSION_NONE is not set
+# CONFIG_INITRAMFS_COMPRESSION_GZIP is not set
+# CONFIG_INITRAMFS_COMPRESSION_BZIP2 is not set
+CONFIG_INITRAMFS_COMPRESSION_LZMA=y
+# CONFIG_INITRAMFS_COMPRESSION_XZ is not set
+# CONFIG_INITRAMFS_COMPRESSION_LZO is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_PANIC_TIMEOUT=1
+# CONFIG_EXPERT is not set
+CONFIG_HAVE_UID16=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+# CONFIG_EMBEDDED is not set
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_PERF_USE_VMALLOC=y
+
+#
+# Kernel Performance Events And Counters
+#
+# CONFIG_PERF_EVENTS is not set
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLUB_DEBUG=y
+CONFIG_COMPAT_BRK=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_PROFILING is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_JUMP_LABEL is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_HAVE_DMA_ATTRS=y
+CONFIG_HAVE_DMA_CONTIGUOUS=y
+CONFIG_USE_GENERIC_SMP_HELPERS=y
+CONFIG_GENERIC_SMP_IDLE_THREAD=y
+CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+CONFIG_HAVE_ARCH_JUMP_LABEL=y
+CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
+CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
+CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
+CONFIG_MODULES_USE_ELF_REL=y
+CONFIG_CLONE_BACKWARDS=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_STOP_MACHINE=y
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+CONFIG_BLK_DEV_BSG=y
+# CONFIG_BLK_DEV_BSGLIB is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_EFI_PARTITION=y
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
+CONFIG_INLINE_READ_UNLOCK=y
+CONFIG_INLINE_READ_UNLOCK_IRQ=y
+CONFIG_INLINE_WRITE_UNLOCK=y
+CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
+CONFIG_MUTEX_SPIN_ON_OWNER=y
+CONFIG_FREEZER=y
+
+#
+# System Type
+#
+CONFIG_MMU=y
+CONFIG_ARCH_MULTIPLATFORM=y
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_BCM2835 is not set
+# CONFIG_ARCH_CNS3XXX is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_GEMINI is not set
+# CONFIG_ARCH_SIRF is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_MXS is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_DOVE is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_W90X900 is not set
+# CONFIG_ARCH_LPC32XX is not set
+# CONFIG_ARCH_TEGRA is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_SHMOBILE is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C24XX is not set
+# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_S5P64X0 is not set
+# CONFIG_ARCH_S5PC100 is not set
+# CONFIG_ARCH_S5PV210 is not set
+# CONFIG_ARCH_EXYNOS is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_U300 is not set
+# CONFIG_ARCH_U8500 is not set
+# CONFIG_ARCH_NOMADIK is not set
+# CONFIG_PLAT_SPEAR is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_VT8500_SINGLE is not set
+
+#
+# Multiple platform selection
+#
+
+#
+# CPU Core family selection
+#
+# CONFIG_ARCH_MULTI_V6 is not set
+CONFIG_ARCH_MULTI_V7=y
+CONFIG_ARCH_MULTI_V6_V7=y
+# CONFIG_ARCH_MULTI_CPU_AUTO is not set
+# CONFIG_ARCH_MVEBU is not set
+# CONFIG_ARCH_BCM is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_KEYBOARD_GPIO_POLLED is not set
+CONFIG_ARCH_HIGHBANK=y
+CONFIG_ARCH_HS=y
+CONFIG_MACH_HS_DT=y
+# CONFIG_ARCH_MXC is not set
+CONFIG_ARCH_SOCFPGA=y
+# CONFIG_ARCH_SUNXI is not set
+CONFIG_ARCH_VEXPRESS=y
+
+#
+# Versatile Express platform type
+#
+# CONFIG_ARCH_VEXPRESS_CORTEX_A5_A9_ERRATA is not set
+# CONFIG_ARCH_VEXPRESS_CA9X4 is not set
+CONFIG_PLAT_VERSATILE_CLCD=y
+CONFIG_PLAT_VERSATILE_SCHED_CLOCK=y
+# CONFIG_ARCH_VT8500 is not set
+# CONFIG_ARCH_ZYNQ is not set
+CONFIG_PLAT_VERSATILE=y
+CONFIG_ARM_TIMER_SP804=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_V7=y
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+CONFIG_CPU_PABRT_V7=y
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_LPAE is not set
+# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
+CONFIG_ARM_THUMB=y
+# CONFIG_ARM_THUMBEE is not set
+# CONFIG_ARM_VIRT_EXT is not set
+CONFIG_SWP_EMULATE=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_OUTER_CACHE=y
+CONFIG_OUTER_CACHE_SYNC=y
+CONFIG_MIGHT_HAVE_CACHE_L2X0=y
+CONFIG_CACHE_L2X0=y
+CONFIG_CACHE_PL310=y
+CONFIG_ARM_L1_CACHE_SHIFT_6=y
+CONFIG_ARM_L1_CACHE_SHIFT=6
+CONFIG_ARM_DMA_MEM_BUFFERABLE=y
+CONFIG_ARM_NR_BANKS=8
+CONFIG_MULTI_IRQ_HANDLER=y
+# CONFIG_ARM_ERRATA_430973 is not set
+# CONFIG_PL310_ERRATA_588369 is not set
+# CONFIG_ARM_ERRATA_720789 is not set
+# CONFIG_PL310_ERRATA_727915 is not set
+# CONFIG_PL310_ERRATA_753970 is not set
+CONFIG_ARM_ERRATA_754322=y
+# CONFIG_ARM_ERRATA_754327 is not set
+# CONFIG_ARM_ERRATA_764369 is not set
+# CONFIG_PL310_ERRATA_769419 is not set
+# CONFIG_ARM_ERRATA_775420 is not set
+CONFIG_ARM_GIC=y
+CONFIG_ICST=y
+
+#
+# Bus support
+#
+CONFIG_ARM_AMBA=y
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_HAVE_SMP=y
+CONFIG_SMP=y
+CONFIG_SMP_ON_UP=y
+CONFIG_ARM_CPU_TOPOLOGY=y
+# CONFIG_SCHED_MC is not set
+# CONFIG_SCHED_SMT is not set
+CONFIG_HAVE_ARM_SCU=y
+CONFIG_ARM_ARCH_TIMER=y
+CONFIG_HAVE_ARM_TWD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_NR_CPUS=4
+CONFIG_HOTPLUG_CPU=y
+CONFIG_LOCAL_TIMERS=y
+CONFIG_ARCH_NR_GPIO=0
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=100
+# CONFIG_THUMB2_KERNEL is not set
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+CONFIG_HAVE_ARCH_PFN_VALID=y
+CONFIG_HIGHMEM=y
+CONFIG_HIGHPTE=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_HAVE_MEMBLOCK=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_COMPACTION=y
+CONFIG_MIGRATION=y
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+CONFIG_CROSS_MEMORY_ATTACH=y
+# CONFIG_CLEANCACHE is not set
+# CONFIG_FRONTSWAP is not set
+CONFIG_FORCE_MAX_ZONEORDER=11
+CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_UACCESS_WITH_MEMCPY is not set
+# CONFIG_SECCOMP is not set
+# CONFIG_CC_STACKPROTECTOR is not set
+# CONFIG_XEN is not set
+
+#
+# Boot options
+#
+CONFIG_USE_OF=y
+CONFIG_ATAGS=y
+# CONFIG_DEPRECATED_PARAM_STRUCT is not set
+CONFIG_ZBOOT_ROM_TEXT=0
+CONFIG_ZBOOT_ROM_BSS=0
+CONFIG_ARM_APPENDED_DTB=y
+# CONFIG_ARM_ATAG_DTB_COMPAT is not set
+CONFIG_CMDLINE=""
+# CONFIG_KEXEC is not set
+# CONFIG_CRASH_DUMP is not set
+CONFIG_AUTO_ZRELADDR=y
+
+#
+# CPU Power Management
+#
+# CONFIG_CPU_IDLE is not set
+# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+# CONFIG_FPE_NWFPE is not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_VFP=y
+CONFIG_VFPv3=y
+CONFIG_NEON=y
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
+CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
+CONFIG_HAVE_AOUT=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+CONFIG_COREDUMP=y
+
+#
+# Power management options
+#
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+CONFIG_PM_SLEEP=y
+CONFIG_PM_SLEEP_SMP=y
+CONFIG_PM_AUTOSLEEP=y
+CONFIG_PM_WAKELOCKS=y
+CONFIG_PM_RUNTIME=y
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+# CONFIG_APM_EMULATION is not set
+CONFIG_PM_CLK=y
+CONFIG_CPU_PM=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_ARM_CPU_SUSPEND=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_PACKET is not set
+CONFIG_UNIX=y
+# CONFIG_UNIX_DIAG is not set
+# CONFIG_NET_KEY is not set
+# CONFIG_INET is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+CONFIG_HAVE_NET_DSA=y
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+# CONFIG_BATMAN_ADV is not set
+# CONFIG_OPENVSWITCH is not set
+CONFIG_RPS=y
+CONFIG_RFS_ACCEL=y
+CONFIG_XPS=y
+CONFIG_BQL=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_WIRELESS=y
+# CONFIG_CFG80211 is not set
+# CONFIG_LIB80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+# CONFIG_CAIF is not set
+# CONFIG_NFC is not set
+CONFIG_HAVE_BPF_JIT=y
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH=""
+# CONFIG_DEVTMPFS is not set
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_GENERIC_CPU_DEVICES is not set
+# CONFIG_DMA_SHARED_BUFFER is not set
+# CONFIG_CMA is not set
+
+#
+# Bus devices
+#
+# CONFIG_CONNECTOR is not set
+# CONFIG_MTD is not set
+CONFIG_DTC=y
+CONFIG_OF=y
+
+#
+# Device Tree and Open Firmware support
+#
+# CONFIG_PROC_DEVICETREE is not set
+# CONFIG_OF_SELFTEST is not set
+CONFIG_OF_FLATTREE=y
+CONFIG_OF_EARLY_FLATTREE=y
+CONFIG_OF_ADDRESS=y
+CONFIG_OF_IRQ=y
+CONFIG_OF_DEVICE=y
+CONFIG_OF_I2C=y
+CONFIG_OF_NET=y
+CONFIG_OF_MDIO=y
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+
+#
+# DRBD disabled because PROC_FS or INET not selected
+#
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_MG_DISK is not set
+
+#
+# Misc devices
+#
+# CONFIG_SENSORS_LIS3LV02D is not set
+# CONFIG_AD525X_DPOT is not set
+# CONFIG_ATMEL_PWM is not set
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_APDS9802ALS is not set
+# CONFIG_ISL29003 is not set
+# CONFIG_ISL29020 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_SENSORS_BH1780 is not set
+# CONFIG_SENSORS_BH1770 is not set
+# CONFIG_SENSORS_APDS990X is not set
+# CONFIG_HMC6352 is not set
+# CONFIG_DS1682 is not set
+# CONFIG_TI_DAC7512 is not set
+# CONFIG_ARM_CHARLCD is not set
+# CONFIG_BMP085_I2C is not set
+# CONFIG_BMP085_SPI is not set
+# CONFIG_USB_SWITCH_FSA9480 is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_AT24 is not set
+# CONFIG_EEPROM_AT25 is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_EEPROM_93XX46 is not set
+
+#
+# Texas Instruments shared transport line discipline
+#
+# CONFIG_TI_ST is not set
+# CONFIG_SENSORS_LIS3_SPI is not set
+# CONFIG_SENSORS_LIS3_I2C is not set
+
+#
+# Altera FPGA firmware download module
+#
+# CONFIG_ALTERA_STAPL is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI_MOD=y
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_BOOT_SYSFS is not set
+# CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+CONFIG_HAVE_PATA_PLATFORM=y
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+CONFIG_ATA_VERBOSE_ERROR=y
+CONFIG_SATA_PMP=y
+
+#
+# Controllers with non-SFF native interface
+#
+# CONFIG_SATA_AHCI_PLATFORM is not set
+CONFIG_ATA_SFF=y
+
+#
+# SFF controllers with custom DMA interface
+#
+CONFIG_ATA_BMDMA=y
+
+#
+# SATA SFF controllers with BMDMA
+#
+CONFIG_SATA_HIGHBANK=y
+CONFIG_SATA_MV=y
+
+#
+# PATA SFF controllers with BMDMA
+#
+# CONFIG_PATA_ARASAN_CF is not set
+
+#
+# PIO-only SFF controllers
+#
+# CONFIG_PATA_PLATFORM is not set
+
+#
+# Generic fallback / legacy drivers
+#
+# CONFIG_MD is not set
+# CONFIG_TARGET_CORE is not set
+CONFIG_NETDEVICES=y
+CONFIG_NET_CORE=y
+# CONFIG_DUMMY is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_MII=y
+# CONFIG_NET_TEAM is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+
+#
+# CAIF transport drivers
+#
+
+#
+# Distributed Switch Architecture drivers
+#
+# CONFIG_NET_DSA_MV88E6XXX is not set
+# CONFIG_NET_DSA_MV88E6060 is not set
+# CONFIG_NET_DSA_MV88E6XXX_NEED_PPU is not set
+# CONFIG_NET_DSA_MV88E6131 is not set
+# CONFIG_NET_DSA_MV88E6123_61_65 is not set
+CONFIG_ETHERNET=y
+CONFIG_NET_CADENCE=y
+# CONFIG_ARM_AT91_ETHER is not set
+# CONFIG_MACB is not set
+CONFIG_NET_VENDOR_BROADCOM=y
+# CONFIG_B44 is not set
+CONFIG_NET_CALXEDA_XGMAC=y
+CONFIG_NET_VENDOR_CIRRUS=y
+# CONFIG_CS89x0 is not set
+# CONFIG_DM9000 is not set
+# CONFIG_DNET is not set
+CONFIG_NET_VENDOR_FARADAY=y
+# CONFIG_FTMAC100 is not set
+# CONFIG_FTGMAC100 is not set
+CONFIG_NET_VENDOR_INTEL=y
+CONFIG_NET_VENDOR_I825XX=y
+CONFIG_NET_VENDOR_MICREL=y
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851 is not set
+# CONFIG_KS8851_MLL is not set
+CONFIG_NET_VENDOR_MICROCHIP=y
+# CONFIG_ENC28J60 is not set
+CONFIG_NET_VENDOR_NATSEMI=y
+CONFIG_NET_VENDOR_8390=y
+# CONFIG_AX88796 is not set
+# CONFIG_ETHOC is not set
+CONFIG_NET_VENDOR_SEEQ=y
+# CONFIG_SEEQ8005 is not set
+CONFIG_NET_VENDOR_SMSC=y
+# CONFIG_SMC91X is not set
+# CONFIG_SMC911X is not set
+CONFIG_SMSC911X=y
+# CONFIG_SMSC911X_ARCH_HOOKS is not set
+CONFIG_NET_VENDOR_STMICRO=y
+CONFIG_STMMAC_ETH=y
+CONFIG_STMMAC_PLATFORM=y
+# CONFIG_STMMAC_DEBUG_FS is not set
+# CONFIG_STMMAC_DA is not set
+CONFIG_STMMAC_RING=y
+# CONFIG_STMMAC_CHAINED is not set
+CONFIG_NET_VENDOR_WIZNET=y
+# CONFIG_WIZNET_W5100 is not set
+# CONFIG_WIZNET_W5300 is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_AT803X_PHY is not set
+# CONFIG_AMD_PHY is not set
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_BCM87XX_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_MICREL_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+# CONFIG_MDIO_BUS_MUX_GPIO is not set
+# CONFIG_MDIO_BUS_MUX_MMIOREG is not set
+# CONFIG_MICREL_KS8995MA is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_USB_IPHETH is not set
+CONFIG_WLAN=y
+# CONFIG_USB_ZD1201 is not set
+# CONFIG_HOSTAP is not set
+# CONFIG_WL_TI is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+# CONFIG_WAN is not set
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+# CONFIG_INPUT_SPARSEKMAP is not set
+# CONFIG_INPUT_MATRIXKMAP is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ADP5588 is not set
+# CONFIG_KEYBOARD_ADP5589 is not set
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_QT1070 is not set
+# CONFIG_KEYBOARD_QT2160 is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+CONFIG_KEYBOARD_GPIO=y
+# CONFIG_KEYBOARD_TCA6416 is not set
+# CONFIG_KEYBOARD_TCA8418 is not set
+# CONFIG_KEYBOARD_MATRIX is not set
+# CONFIG_KEYBOARD_LM8333 is not set
+# CONFIG_KEYBOARD_MAX7359 is not set
+# CONFIG_KEYBOARD_MCS is not set
+# CONFIG_KEYBOARD_MPR121 is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
+# CONFIG_KEYBOARD_SAMSUNG is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+CONFIG_MOUSE_PS2_ALPS=y
+CONFIG_MOUSE_PS2_LOGIPS2PP=y
+CONFIG_MOUSE_PS2_SYNAPTICS=y
+CONFIG_MOUSE_PS2_TRACKPOINT=y
+# CONFIG_MOUSE_PS2_ELANTECH is not set
+# CONFIG_MOUSE_PS2_SENTELIC is not set
+# CONFIG_MOUSE_PS2_TOUCHKIT is not set
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_APPLETOUCH is not set
+# CONFIG_MOUSE_BCM5974 is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_MOUSE_GPIO is not set
+# CONFIG_MOUSE_SYNAPTICS_I2C is not set
+# CONFIG_MOUSE_SYNAPTICS_USB is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_MXT224E=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_HI6421_ONKEY=y
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_SERIO_AMBAKMI=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_SERIO_ALTERA_PS2 is not set
+# CONFIG_SERIO_PS2MULT is not set
+# CONFIG_SERIO_ARC_PS2 is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_VT_CONSOLE_SLEEP=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_N_GSM is not set
+# CONFIG_TRACE_SINK is not set
+CONFIG_DEVKMEM=y
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_AMBA_PL010 is not set
+CONFIG_SERIAL_AMBA_PL011=y
+CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
+# CONFIG_SERIAL_MAX3100 is not set
+# CONFIG_SERIAL_MAX310X is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_SCCNXP is not set
+# CONFIG_SERIAL_TIMBERDALE is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
+# CONFIG_SERIAL_IFX6X60 is not set
+# CONFIG_SERIAL_XILINX_PS_UART is not set
+# CONFIG_SERIAL_ARC is not set
+# CONFIG_HVC_DCC is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_HW_RANDOM_TIMERIOMEM is not set
+# CONFIG_HW_RANDOM_ATMEL is not set
+# CONFIG_HW_RANDOM_EXYNOS is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
+# CONFIG_I2C_CHARDEV is not set
+# CONFIG_I2C_MUX is not set
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_CBUS_GPIO is not set
+CONFIG_I2C_DESIGNWARE_CORE=y
+CONFIG_I2C_DESIGNWARE_PLATFORM=y
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_NOMADIK is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_PXA_PCI is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_VERSATILE is not set
+# CONFIG_I2C_XILINX is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_DIOLAN_U2C is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_ALTERA is not set
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_GPIO is not set
+# CONFIG_SPI_OC_TINY is not set
+CONFIG_SPI_PL022=y
+# CONFIG_SPI_PXA2XX_PCI is not set
+# CONFIG_SPI_SC18IS602 is not set
+# CONFIG_SPI_XCOMM is not set
+# CONFIG_SPI_XILINX is not set
+# CONFIG_SPI_DESIGNWARE is not set
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+# CONFIG_HSI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+
+#
+# PPS generators support
+#
+
+#
+# PTP clock support
+#
+# CONFIG_PTP_1588_CLOCK is not set
+
+#
+# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
+#
+# CONFIG_PTP_1588_CLOCK_PCH is not set
+CONFIG_PINCTRL=y
+
+#
+# Pin controllers
+#
+CONFIG_PINMUX=y
+CONFIG_PINCONF=y
+CONFIG_GENERIC_PINCONF=y
+# CONFIG_DEBUG_PINCTRL is not set
+CONFIG_PINCTRL_SINGLE=y
+# CONFIG_PINCTRL_EXYNOS4 is not set
+# CONFIG_PINCTRL_EXYNOS5440 is not set
+CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+CONFIG_OF_GPIO=y
+# CONFIG_DEBUG_GPIO is not set
+CONFIG_GPIO_SYSFS=y
+
+#
+# Memory mapped GPIO drivers:
+#
+# CONFIG_GPIO_GENERIC_PLATFORM is not set
+# CONFIG_GPIO_EM is not set
+CONFIG_GPIO_PL061=y
+# CONFIG_GPIO_TS5500 is not set
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX7300 is not set
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCF857X is not set
+# CONFIG_GPIO_SX150X is not set
+# CONFIG_GPIO_ADP5588 is not set
+# CONFIG_GPIO_ADNP is not set
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_GPIO_MC33880 is not set
+# CONFIG_GPIO_74X164 is not set
+
+#
+# AC97 GPIO expanders:
+#
+
+#
+# MODULbus GPIO expanders:
+#
+
+#
+# USB GPIO expanders:
+#
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_POWER_AVS is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Native drivers
+#
+# CONFIG_SENSORS_AD7314 is not set
+# CONFIG_SENSORS_AD7414 is not set
+# CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADCXX is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ADT7410 is not set
+# CONFIG_SENSORS_ADT7411 is not set
+# CONFIG_SENSORS_ADT7462 is not set
+# CONFIG_SENSORS_ADT7470 is not set
+# CONFIG_SENSORS_ADT7475 is not set
+# CONFIG_SENSORS_ASC7621 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS620 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_F75375S is not set
+# CONFIG_SENSORS_G760A is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_GPIO_FAN is not set
+# CONFIG_SENSORS_HIH6130 is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_JC42 is not set
+# CONFIG_SENSORS_LINEAGE is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM70 is not set
+# CONFIG_SENSORS_LM73 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_LM93 is not set
+# CONFIG_SENSORS_LTC4151 is not set
+# CONFIG_SENSORS_LTC4215 is not set
+# CONFIG_SENSORS_LTC4245 is not set
+# CONFIG_SENSORS_LTC4261 is not set
+# CONFIG_SENSORS_LM95241 is not set
+# CONFIG_SENSORS_LM95245 is not set
+# CONFIG_SENSORS_MAX1111 is not set
+# CONFIG_SENSORS_MAX16065 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX1668 is not set
+# CONFIG_SENSORS_MAX197 is not set
+# CONFIG_SENSORS_MAX6639 is not set
+# CONFIG_SENSORS_MAX6642 is not set
+# CONFIG_SENSORS_MAX6650 is not set
+# CONFIG_SENSORS_MCP3021 is not set
+# CONFIG_SENSORS_NTC_THERMISTOR is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_PMBUS is not set
+# CONFIG_SENSORS_SHT15 is not set
+# CONFIG_SENSORS_SHT21 is not set
+# CONFIG_SENSORS_SMM665 is not set
+# CONFIG_SENSORS_DME1737 is not set
+# CONFIG_SENSORS_EMC1403 is not set
+# CONFIG_SENSORS_EMC2103 is not set
+# CONFIG_SENSORS_EMC6W201 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_SCH56XX_COMMON is not set
+# CONFIG_SENSORS_ADS1015 is not set
+# CONFIG_SENSORS_ADS7828 is not set
+# CONFIG_SENSORS_ADS7871 is not set
+# CONFIG_SENSORS_AMC6821 is not set
+# CONFIG_SENSORS_INA2XX is not set
+# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP102 is not set
+# CONFIG_SENSORS_TMP401 is not set
+# CONFIG_SENSORS_TMP421 is not set
+# CONFIG_SENSORS_VEXPRESS is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83795 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83L786NG is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_THERMAL is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+CONFIG_BCMA_POSSIBLE=y
+
+#
+# Broadcom specific AMBA
+#
+# CONFIG_BCMA is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_88PM860X is not set
+# CONFIG_MFD_88PM800 is not set
+# CONFIG_MFD_88PM805 is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+# CONFIG_MFD_TI_AM335X_TSCADC is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_HTC_I2CPLD is not set
+# CONFIG_MFD_LM3533 is not set
+# CONFIG_TPS6105X is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_TPS6507X is not set
+# CONFIG_MFD_TPS65217 is not set
+# CONFIG_MFD_TPS6586X is not set
+# CONFIG_MFD_TPS65910 is not set
+# CONFIG_MFD_TPS65912_I2C is not set
+# CONFIG_MFD_TPS65912_SPI is not set
+# CONFIG_MFD_TPS80031 is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_TWL6040_CORE is not set
+# CONFIG_MFD_STMPE is not set
+# CONFIG_MFD_TC3589X is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_SMSC is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_MFD_DA9052_SPI is not set
+# CONFIG_MFD_DA9052_I2C is not set
+# CONFIG_MFD_DA9055 is not set
+# CONFIG_PMIC_ADP5520 is not set
+# CONFIG_MFD_LP8788 is not set
+# CONFIG_MFD_MAX77686 is not set
+# CONFIG_MFD_MAX77693 is not set
+# CONFIG_MFD_MAX8907 is not set
+# CONFIG_MFD_MAX8925 is not set
+# CONFIG_MFD_MAX8997 is not set
+# CONFIG_MFD_MAX8998 is not set
+# CONFIG_MFD_SEC_CORE is not set
+# CONFIG_MFD_ARIZONA_I2C is not set
+# CONFIG_MFD_ARIZONA_SPI is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X_I2C is not set
+# CONFIG_MFD_WM831X_SPI is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_WM8994 is not set
+# CONFIG_MFD_PCF50633 is not set
+CONFIG_MFD_R63306=y
+# CONFIG_MFD_MC13XXX_SPI is not set
+# CONFIG_MFD_MC13XXX_I2C is not set
+# CONFIG_ABX500_CORE is not set
+# CONFIG_EZX_PCAP is not set
+# CONFIG_MFD_WL1273_CORE is not set
+# CONFIG_MFD_TPS65090 is not set
+# CONFIG_MFD_AAT2870_CORE is not set
+# CONFIG_MFD_RC5T583 is not set
+# CONFIG_MFD_SYSCON is not set
+# CONFIG_MFD_PALMAS is not set
+# CONFIG_MFD_VIPERBOARD is not set
+# CONFIG_MFD_RETU is not set
+# CONFIG_MFD_AS3711 is not set
+CONFIG_MFD_HI6421_PMIC=y
+CONFIG_VEXPRESS_CONFIG=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_HI6421=y
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+# CONFIG_DRM is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_WMT_GE_ROPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+CONFIG_FB_ARMCLCD=y
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_SMSCUFX is not set
+# CONFIG_FB_UDL is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_BROADSHEET is not set
+# CONFIG_FB_AUO_K190X is not set
+# CONFIG_EXYNOS_VIDEO is not set
+CONFIG_FB_HI3620=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Console display driver support
+#
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_LOGO is not set
+# CONFIG_FB_SSD1307 is not set
+# CONFIG_SOUND is not set
+
+#
+# HID support
+#
+CONFIG_HID=y
+# CONFIG_HIDRAW is not set
+# CONFIG_UHID is not set
+CONFIG_HID_GENERIC=y
+
+#
+# Special HID drivers
+#
+CONFIG_HID_A4TECH=y
+# CONFIG_HID_ACRUX is not set
+CONFIG_HID_APPLE=y
+# CONFIG_HID_AUREAL is not set
+CONFIG_HID_BELKIN=y
+CONFIG_HID_CHERRY=y
+CONFIG_HID_CHICONY=y
+CONFIG_HID_CYPRESS=y
+# CONFIG_HID_DRAGONRISE is not set
+# CONFIG_HID_EMS_FF is not set
+CONFIG_HID_EZKEY=y
+# CONFIG_HID_HOLTEK is not set
+# CONFIG_HID_KEYTOUCH is not set
+# CONFIG_HID_KYE is not set
+# CONFIG_HID_UCLOGIC is not set
+# CONFIG_HID_WALTOP is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_TWINHAN is not set
+CONFIG_HID_KENSINGTON=y
+# CONFIG_HID_LCPOWER is not set
+# CONFIG_HID_LENOVO_TPKBD is not set
+CONFIG_HID_LOGITECH=y
+# CONFIG_HID_LOGITECH_DJ is not set
+# CONFIG_LOGITECH_FF is not set
+# CONFIG_LOGIRUMBLEPAD2_FF is not set
+# CONFIG_LOGIG940_FF is not set
+# CONFIG_LOGIWHEELS_FF is not set
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MONTEREY=y
+# CONFIG_HID_MULTITOUCH is not set
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_ORTEK is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_PICOLCD is not set
+# CONFIG_HID_PRIMAX is not set
+# CONFIG_HID_ROCCAT is not set
+# CONFIG_HID_SAITEK is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_SPEEDLINK is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
+# CONFIG_HID_TIVO is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_ZEROPLUS is not set
+# CONFIG_HID_ZYDACRON is not set
+# CONFIG_HID_SENSOR_HUB is not set
+
+#
+# USB HID support
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# I2C HID support
+#
+# CONFIG_I2C_HID is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB_ARCH_HAS_XHCI is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_COMMON=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_MON is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_ISP1760_HCD=y
+# CONFIG_USB_ISP1362_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_CHIPIDEA is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_REALTEK is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_STORAGE_ENE_UB6250 is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_YUREX is not set
+# CONFIG_USB_EZUSB_FX2 is not set
+
+#
+# USB Physical Layer drivers
+#
+# CONFIG_USB_ISP1301 is not set
+# CONFIG_USB_RCAR_PHY is not set
+# CONFIG_USB_GADGET is not set
+
+#
+# OTG and related infrastructure
+#
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_USB_ULPI is not set
+# CONFIG_NOP_USB_XCEIV is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+# CONFIG_MMC_CLKGATE is not set
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+CONFIG_MMC_ARMMMCI=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+# CONFIG_MMC_SDHCI_PXAV3 is not set
+# CONFIG_MMC_SDHCI_PXAV2 is not set
+CONFIG_MMC_DW=y
+CONFIG_MMC_DW_IDMAC=y
+CONFIG_MMC_DW_PLTFM=y
+CONFIG_MMC_DW_HISILICON=y
+# CONFIG_MMC_VUB300 is not set
+# CONFIG_MMC_USHC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_EDAC=y
+CONFIG_EDAC_LEGACY_SYSFS=y
+# CONFIG_EDAC_DEBUG is not set
+CONFIG_EDAC_MM_EDAC=y
+CONFIG_EDAC_HIGHBANK_MC=y
+CONFIG_EDAC_HIGHBANK_L2=y
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_DS3232 is not set
+CONFIG_RTC_DRV_HI6421=y
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_ISL12022 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8523 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_BQ32K is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
+# CONFIG_RTC_DRV_EM3027 is not set
+# CONFIG_RTC_DRV_RV3029C2 is not set
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_M41T93 is not set
+# CONFIG_RTC_DRV_M41T94 is not set
+# CONFIG_RTC_DRV_DS1305 is not set
+# CONFIG_RTC_DRV_DS1390 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_DS3234 is not set
+# CONFIG_RTC_DRV_PCF2123 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_MSM6242 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_RP5C01 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+# CONFIG_RTC_DRV_DS2404 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_RTC_DRV_PL030 is not set
+CONFIG_RTC_DRV_PL031=y
+# CONFIG_RTC_DRV_SNVS is not set
+CONFIG_DMADEVICES=y
+# CONFIG_DMADEVICES_DEBUG is not set
+
+#
+# DMA Devices
+#
+CONFIG_AMBA_PL08X=y
+# CONFIG_DW_DMAC is not set
+# CONFIG_TIMB_DMA is not set
+CONFIG_PL330_DMA=y
+CONFIG_K3_DMA=y
+CONFIG_DMA_ENGINE=y
+
+#
+# DMA Clients
+#
+# CONFIG_NET_DMA is not set
+# CONFIG_ASYNC_TX_DMA is not set
+# CONFIG_DMATEST is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+
+#
+# Virtio drivers
+#
+# CONFIG_VIRTIO_MMIO is not set
+
+#
+# Microsoft Hyper-V guest support
+#
+# CONFIG_STAGING is not set
+CONFIG_CLKDEV_LOOKUP=y
+CONFIG_HAVE_CLK_PREPARE=y
+CONFIG_COMMON_CLK=y
+
+#
+# Common Clock Framework
+#
+# CONFIG_COMMON_CLK_DEBUG is not set
+CONFIG_COMMON_CLK_VERSATILE=y
+
+#
+# Hardware Spinlock drivers
+#
+CONFIG_CLKSRC_MMIO=y
+CONFIG_DW_APB_TIMER=y
+CONFIG_DW_APB_TIMER_OF=y
+CONFIG_IOMMU_SUPPORT=y
+CONFIG_OF_IOMMU=y
+
+#
+# Remoteproc drivers (EXPERIMENTAL)
+#
+# CONFIG_STE_MODEM_RPROC is not set
+
+#
+# Rpmsg drivers (EXPERIMENTAL)
+#
+# CONFIG_VIRT_DRIVERS is not set
+# CONFIG_PM_DEVFREQ is not set
+# CONFIG_EXTCON is not set
+# CONFIG_MEMORY is not set
+# CONFIG_IIO is not set
+# CONFIG_PWM is not set
+# CONFIG_IPACK_BUS is not set
+
+#
+# File systems
+#
+CONFIG_DCACHE_WORD_ACCESS=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_DEFAULTS_TO_ORDERED=y
+CONFIG_EXT3_FS_XATTR=y
+CONFIG_EXT4_FS=y
+CONFIG_JBD=y
+CONFIG_JBD2=y
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_FANOTIFY is not set
+# CONFIG_QUOTA is not set
+# CONFIG_QUOTACTL is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+# CONFIG_VFAT_FS is not set
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_LOGFS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX6FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_PSTORE is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_F2FS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_MAC_ROMAN is not set
+# CONFIG_NLS_MAC_CELTIC is not set
+# CONFIG_NLS_MAC_CENTEURO is not set
+# CONFIG_NLS_MAC_CROATIAN is not set
+# CONFIG_NLS_MAC_CYRILLIC is not set
+# CONFIG_NLS_MAC_GAELIC is not set
+# CONFIG_NLS_MAC_GREEK is not set
+# CONFIG_NLS_MAC_ICELAND is not set
+# CONFIG_NLS_MAC_INUIT is not set
+# CONFIG_NLS_MAC_ROMANIAN is not set
+# CONFIG_NLS_MAC_TURKISH is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Kernel hacking
+#
+CONFIG_PRINTK_TIME=y
+CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_READABLE_ASM is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_SECTION_MISMATCH is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_LOCKUP_DETECTOR=y
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=1
+# CONFIG_PANIC_ON_OOPS is not set
+CONFIG_PANIC_ON_OOPS_VALUE=0
+# CONFIG_DETECT_HUNG_TASK is not set
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
+CONFIG_HAVE_DEBUG_KMEMLEAK=y
+# CONFIG_DEBUG_KMEMLEAK is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_SPARSE_RCU_POINTER is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_ATOMIC_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_HIGHMEM is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+CONFIG_DEBUG_MEMORY_INIT=y
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_TEST_LIST_SORT is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+CONFIG_RCU_CPU_STALL_TIMEOUT=21
+# CONFIG_RCU_CPU_STALL_INFO is not set
+# CONFIG_RCU_TRACE is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
+# CONFIG_DEBUG_PER_CPU_MAPS is not set
+# CONFIG_LKDTM is not set
+# CONFIG_NOTIFIER_ERROR_INJECTION is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
+CONFIG_HAVE_C_RECORDMCOUNT=y
+CONFIG_TRACING_SUPPORT=y
+# CONFIG_FTRACE is not set
+CONFIG_DYNAMIC_DEBUG=y
+# CONFIG_DMA_API_DEBUG is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+# CONFIG_TEST_KSTRTOX is not set
+# CONFIG_STRICT_DEVMEM is not set
+CONFIG_ARM_UNWIND=y
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_LL is not set
+CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S"
+# CONFIG_OC_ETM is not set
+# CONFIG_PID_IN_CONTEXTIDR is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY_DMESG_RESTRICT is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_DEFAULT_SECURITY=""
+# CONFIG_CRYPTO is not set
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_STRNCPY_FROM_USER=y
+CONFIG_GENERIC_STRNLEN_USER=y
+CONFIG_GENERIC_PCI_IOMAP=y
+CONFIG_GENERIC_IO=y
+CONFIG_PERCPU_RWSEM=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC32_SELFTEST is not set
+CONFIG_CRC32_SLICEBY8=y
+# CONFIG_CRC32_SLICEBY4 is not set
+# CONFIG_CRC32_SARWATE is not set
+# CONFIG_CRC32_BIT is not set
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+# CONFIG_CRC8 is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_XZ_DEC=y
+CONFIG_XZ_DEC_X86=y
+CONFIG_XZ_DEC_POWERPC=y
+CONFIG_XZ_DEC_IA64=y
+CONFIG_XZ_DEC_ARM=y
+CONFIG_XZ_DEC_ARMTHUMB=y
+CONFIG_XZ_DEC_SPARC=y
+CONFIG_XZ_DEC_BCJ=y
+# CONFIG_XZ_DEC_TEST is not set
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_DECOMPRESS_BZIP2=y
+CONFIG_DECOMPRESS_LZMA=y
+CONFIG_DECOMPRESS_XZ=y
+CONFIG_DECOMPRESS_LZO=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_DMA=y
+CONFIG_CPU_RMAP=y
+CONFIG_DQL=y
+CONFIG_NLATTR=y
+CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
+# CONFIG_AVERAGE is not set
+# CONFIG_CORDIC is not set
+# CONFIG_DDR is not set
diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig
index 2e67a272df70..2f8816bc9c69 100644
--- a/arch/arm/configs/multi_v7_defconfig
+++ b/arch/arm/configs/multi_v7_defconfig
@@ -6,6 +6,8 @@ CONFIG_MACH_ARMADA_370=y
CONFIG_ARCH_SIRF=y
CONFIG_MACH_ARMADA_XP=y
CONFIG_ARCH_HIGHBANK=y
+CONFIG_MACH_HI4511=y
+CONFIG_ARCH_HS=y
CONFIG_ARCH_SOCFPGA=y
CONFIG_ARCH_SUNXI=y
CONFIG_ARCH_WM8850=y
diff --git a/arch/arm/include/debug/hisilicon.S b/arch/arm/include/debug/hisilicon.S
new file mode 100644
index 000000000000..2da0f6d55477
--- /dev/null
+++ b/arch/arm/include/debug/hisilicon.S
@@ -0,0 +1,35 @@
+/*
+ * Early serial output macro for Hisilicon SoC
+ *
+ * Copyright (C) 2012-2013 Linaro Ltd.
+ *
+ * Haojian Zhuang <haojian.zhuang@linaro.org>
+ *
+ * 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.
+*/
+
+#define HI3620_UART0_PHYS_BASE 0xfcb00000
+#define HI3620_UART0_VIRT_BASE 0xfeb00000
+
+#define HI3716_UART0_PHYS_BASE 0xf8b00000
+#define HI3716_UART0_VIRT_BASE 0xfeb00000
+
+#if defined(CONFIG_DEBUG_HI3620_UART0)
+ .macro addruart,rp,rv,tmp
+ ldr \rp, =HI3620_UART0_PHYS_BASE
+ ldr \rv, =HI3620_UART0_VIRT_BASE
+ .endm
+
+#include <asm/hardware/debug-pl01x.S>
+
+#elif defined(CONFIG_DEBUG_HI3716_UART0)
+ .macro addruart,rp,rv,tmp
+ ldr \rp, =HI3716_UART0_PHYS_BASE
+ ldr \rv, =HI3716_UART0_VIRT_BASE
+ .endm
+
+#include <asm/hardware/debug-pl01x.S>
+
+#endif
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 6002fe06b124..1f1eabd7b6be 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -470,6 +470,13 @@ void __init smp_setup_processor_id(void)
for (i = 1; i < nr_cpu_ids; ++i)
cpu_logical_map(i) = i == cpu ? 0 : i;
+ /*
+ * clear __my_cpu_offset on boot CPU to avoid hang caused by
+ * using percpu variable early, for example, lockdep will
+ * access percpu variable inside lock_release
+ */
+ set_my_cpu_offset(0);
+
printk(KERN_INFO "Booting Linux on physical CPU 0x%x\n", mpidr);
}
diff --git a/arch/arm/mach-hs/Kconfig b/arch/arm/mach-hs/Kconfig
new file mode 100644
index 000000000000..6fbc2e3ed560
--- /dev/null
+++ b/arch/arm/mach-hs/Kconfig
@@ -0,0 +1,21 @@
+config ARCH_HS
+ bool "Hisilicon Hi36xx/Hi37xx family" if ARCH_MULTI_V7
+ select CACHE_L2X0
+ select CACHE_PL310
+ select PINCTRL
+ select PINCTRL_SINGLE
+ select SERIAL_AMBA_PL011
+ select SERIAL_AMBA_PL011_CONSOLE
+ help
+ Support for Hislicon Hi36xx/Hi37xx processor family
+
+if ARCH_HS
+
+config MACH_HS_DT
+ bool "Hisilicon Development Board"
+ default y
+ help
+ Say 'Y' here if you want to support the Hisilicon Development
+ Board.
+
+endif
diff --git a/arch/arm/mach-hs/Makefile b/arch/arm/mach-hs/Makefile
new file mode 100644
index 000000000000..4d7b57a64214
--- /dev/null
+++ b/arch/arm/mach-hs/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for Hisilicon Hi36xx/Hi37xx processors line
+#
+
+obj-$(CONFIG_MACH_HS_DT) += hs-dt.o system.o
+obj-$(CONFIG_SMP) += platsmp.o
+obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
+obj-$(CONFIG_PM) += pm.o
+obj-$(CONFIG_PM) += hilpm-cpugodp.o
+obj-$(CONFIG_PM) += lowpmregs.o
diff --git a/arch/arm/mach-hs/core.h b/arch/arm/mach-hs/core.h
new file mode 100644
index 000000000000..efc9e5db80fb
--- /dev/null
+++ b/arch/arm/mach-hs/core.h
@@ -0,0 +1,28 @@
+#ifndef __HISILICON_CORE_H
+#define __HISILICON_CORE_H
+
+#include <linux/init.h>
+
+extern void __iomem *hs_sctrl_base;
+extern void __iomem *hs_secram_va_base;
+extern void __iomem *hs_a9per_va_base;
+extern void __iomem *hs_pctrl_va_base;
+extern void __iomem *hs_pmuspi_va_base;
+
+extern void hs_set_cpu_jump(int cpu, void *jump_addr);
+extern int hs_get_cpu_jump(int cpu);
+extern void secondary_startup(void);
+extern void hs_map_io(void);
+extern struct smp_operations hs_smp_ops;
+extern void hs_restart(char mode, const char *cmd);
+
+extern void __init hs_hotplug_init(void);
+extern void hs_cpu_die(unsigned int cpu);
+extern int hs_cpu_kill(unsigned int cpu);
+extern void hs_set_cpu(int cpu, bool enable);
+
+#ifdef CONFIG_PM
+extern void pmulowpower(int isuspend);
+#endif
+
+#endif
diff --git a/arch/arm/mach-hs/hilpm-cpugodp.S b/arch/arm/mach-hs/hilpm-cpugodp.S
new file mode 100644
index 000000000000..e87d647ed2d1
--- /dev/null
+++ b/arch/arm/mach-hs/hilpm-cpugodp.S
@@ -0,0 +1,1006 @@
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/cp15.h>
+#include "hipm.h"
+
+.extern hs_a9per_va_base
+.extern hs_secram_va_base
+.extern hs_sctrl_base
+
+/**physical address to virtal or virtual to physical**/
+.macro addr_proc, rx, rxt, p, v
+ LDR \rxt, =\p
+ SUB \rx, \rxt
+ LDR \rxt, =\v
+ ADD \rx, \rxt
+.endm
+
+/**physical to virtual**/
+.macro p2v, rx, rxt, p, v
+ addr_proc \rx, \rxt, \p, \v
+.endm
+
+/**virtual to physical**/
+.macro v2p, rx, rxt, v, p
+ addr_proc \rx, \rxt, \v, \p
+.endm
+
+/*
+ *------------------------------------------------------------------------------
+ * Function: hilpm_cpu_godpsleep
+ *
+ * this function is the low level interface when deep sleep.
+ *
+ */
+
+ENTRY (hilpm_cpu_godpsleep)
+ /* According to Procedure Call Standard for ARM, r0-r3 dont need to
+ * be preserved
+ */
+ STMFD sp!, {r4-r11, lr}
+
+ LDR r8, hi_cpu_godpsleep_phybase
+ @r8 store the PHY address of stored_ctx
+ LDR r0, =(hs_secram_va_base)
+ LDR r0, [r0]
+ LDR r9, =(A9_PRE_STORE_DATA_ADDR_OFFSET)
+ ADD r9, r9, r0 @r9 store the pre-store address which in securam
+
+ /* Some A9 Contexts need be protected before MMU and cache disabled
+ * r9 store the address in securam, to store some critial cp15
+ * register which has relationship with MMU operation
+ */
+
+ MOV r1, #0
+ MCR p15, 0, r1, c7, c5, 0 @ Invalidate entire instruction cache
+ @ and flush branch predictor arrays
+ /* get the CPUID */
+ MRC p15, 0, r0, c0, c0, 5 @ Read CPU MPIDR
+ AND r0, r0, #0x03 @ Mask off, leaving the CPU ID field
+
+save_ctx:
+
+ /* save critial CP15 register before MMU Disabled
+ * CPU_ID save in r0
+ * save CTRL_Register in r1
+ * save Aux_Ctrl_register in r2
+ * TTBR0 in r3
+ * TTBR1 in r4
+ * TTBCR in r5
+ * DAC in r6
+ */
+ mrc p15, 0, r1, c1, c0, 0 @ sctlr
+ mrc p15, 0, r2, c1, c0, 1 @ actlr
+ mrc p15, 0, r3, c2, c0, 0 @ TTBR0
+ mrc p15, 0, r4, c2, c0, 1 @ TTBR1
+ mrc p15, 0, r5, c2, c0, 2 @ TTBCR
+ mrc p15, 0, r6, c3, c0, 0 @ domain access control reg
+
+ /* Notes: MMU is enabled, using the pre-store addree which stored in R9
+ * r0,[r9] @offset0 store the CPU_ID
+ * r1,[r9,#0x4] @CTRL_Register
+ * r2,[r9,#0x8] @Aux_Ctrl_register
+ * r3,[r9,#0xc] @TTBR0
+ * r4,[r9,#0x10] @TTBR1
+ * r5,[r9,#0x14] @TTBCR
+ * r6,[r9,#0x18] @DAC
+ */
+ STMIA r9,{r0-r6}
+
+ /* now Clean and Invalid D-Cache, and Disable Cache */
+ mov r0, #0
+ mcr p15, 0, r0, c7, c5, 4 @ Flush prefetch buffer
+ mcr p15, 0, r0, c7, c5, 6 @ Invalidate branch predictor array
+ mcr p15, 0, r0, c8, c5, 0 @ Invalidate instruction TLB
+ mcr p15, 0, r0, c8, c6, 0 @ Invalidate data TLB
+
+ /* protect r9 to r6 while clean and invalid l1-cache
+ * now r9 can be released for free use
+ * r8 is reserved which store the PHY address
+ */
+ mov r6,r9
+
+ /* Flush the entire cache system: Dcache and Icache
+ * Corrupted registers: R0~R3
+ */
+ bl v7_flush_kern_cache_all @ Flush the entire cache system
+
+ mov r0, #0
+ mcr p15, 0, r0, c7, c1, 6 @ BPIALLIS
+ mcr p15, 0, r0, c8, c3, 0
+
+ mov r0, #0
+ mcr p15, 0, r0, c1, c0, 1 @ A9 exit coherency now
+
+ /* After clean and invalid cache, we need disable
+ * D-Cache immediately
+ */
+
+ /* Data Cache Disable */
+ mrc p15, 0, r0, c1, c0, 0
+ bic r0, r0, #(CR_C) @ Dcache disable
+ mcr p15, 0, r0, c1, c0, 0
+
+ /* save back Secruram stored data address
+ * r10 store the pre-store ctx address in securam
+ * r6 can be releaseed for free use
+ */
+ mov r10, r6
+
+ /* Before MMU is disabled, to
+ * Convert r10 from virtual address to physical address
+ * Note: r10 is the address in SECRAM to save tmp data
+ */
+ LDR r0, =(hs_secram_va_base)
+ LDR r0, [r0]
+ SUB r10, r10, r0 @ r10 is offset to SECRAM base
+ LDR r0, =(REG_BASE_SECRAM)
+ ADD r10, r10, r0 @ r10 is physical address
+
+ /* write domain access to get the domain access right */
+ LDR r0, =0xFFFFFFFF
+ MCR p15, 0, r0, c3, c0, 0
+
+ /*read TTBCR*/
+ mrc p15, 0, r7, c2, c0, 2
+ and r7, #0x7
+ cmp r7, #0x0
+ beq create_idmap
+ttbr_error:
+ @TTBR1 not supports
+ b ttbr_error
+
+create_idmap:
+ /**read TTBR0 registers**/
+ mrc p15, 0, r2, c2, c0, 0 @ r2: translation table base register 0
+ ldr r5, =TTBRBIT_MASK @ 0xFFFFC000, high 18 bits
+ and r2, r5 @ r2 = TTBR0's high 18 bits
+ ldr r4, =(hisi_v2p(disable_mmu)) @ r4, pa(disable_mmu)
+ ldr r5, =TABLE_INDEX_MASK @ 0xFFF00000, top 12 bits.
+ @ why not 14?
+ and r4, r5 @ r4 = keeps the top 12 bits.
+ ldr r1, =TABLE_ENTRY
+ @ r1 = 0x00000C02
+ @ why 0x0C02? these are ttb property bits.
+ @ any change in v3.8?
+ add r1, r1, r4 @ r1 = top 12 bits of pa(disable_mmu) | 0x0C02
+ lsr r4, #18 @ r4 = r4 >> 18
+ add r2, r4 @ r2 = r2 + r4, TTBR0's high 18 bits +
+ @ r4's top 14 bits (shifted to low 14 bits)
+
+ /**r2 virtual addr for TLB**/
+ p2v r2, r4, K3_PLAT_PHYS_OFFSET, PAGE_OFFSET
+
+ @ now, r2 is the virtual address of disable_mmu() code part.
+ @ what if disable_mmu() code part cross two or
+ @ more translation table section?
+ @ /* TODO: need manual checking now. should be fixed in future */
+
+ /**read the TLB**/
+ LDR r7, [r2]
+
+ /**config the identy mapping**/
+ STR r1, [r2] @ change the TLB its to it's physical address.
+
+ /**r9 virtual addr for tlb**/
+ mov r9, r2
+
+ /**r11 virtual addr of the enable_mmu**/
+ ADR r11, mmu_enalbed
+ NOP
+ NOP
+ NOP
+
+ LDR r6, =(hisi_v2p(ready_to_store))
+ LDR pc, =(hisi_v2p(disable_mmu))
+
+disable_mmu:
+ instr_sync
+
+ /*disable MMU*/
+ MRC p15, 0, r0, c1, c0, 0
+ BIC r0, r0, #(CR_M | CR_C) @ MMU disable, Dcache disable
+ MCR p15, 0, r0, c1, c0, 0
+
+ /* invalidate I & D TLBs */
+ LDR r0,=0x0
+ MCR p15, 0, r0, c8, c7, 0
+ instr_sync
+
+ MOV pc, r6
+
+ /* From this scratch , MMU is Disabled */
+ready_to_store:
+ /* move critical data from securam to DDR (L1/l2 unaccessable)
+ * r0,[r10] offset0 store the Slave CPU Return Addres
+ * if offset0 is 0, that means this cpu has
+ * not booted up yet
+ * r1,[r10,#0x4] @CTRL_Register
+ * r2,[r10,#0x8] @Aux_Ctrl_register
+ * r3,[r10,#0xC] @TTBR0
+ * r4,[r10,#0x10] @TTBR1
+ * r5,[r10,#0x14] @TTBCR
+ * r6,[r10,#0x18] @DAC
+ * r7,[r10,#0x1C] direct mapping first level descriptor
+ * r9,[r10,#0x20] virtual addr for the first level descriptor
+ * r11,[r10, #0x24] enable_mmu virtual addr
+ */
+
+ /* r10 is physical address of SECURAM to save tmp data
+ * Note: Converted before MMU is disabled
+ */
+ LDMIA r10, {r0-r6}
+
+ mrc p15, 0, r3, c2, c0, 0 @ TTBR0
+ mrc p15, 0, r4, c2, c0, 1 @ TTBR1
+ mrc p15, 0, r5, c2, c0, 2 @ TTBCR
+
+ /* r8 is addr to store data in ddr */
+ STMIA r8, {r0-r7, r9, r11}
+
+all_to_store:
+
+ /* R6/R10 can be release now
+ * R9/R8 is reserved
+ */
+ add r9, r8, #SUSPEND_STORE_RESEVED_UNIT
+
+ /* save CP15 register */
+ mrc p15, 2, r0, c0, c0, 0 @ csselr
+ mrc p15, 0, r4, c15, c0, 0 @ pctlr
+ stmia r9!, {r0, r4}
+
+ mrc p15, 0, r0, c15, c0, 1 @ diag
+ mrc p15, 0, r1, c1, c0, 2 @ cpacr
+ stmia r9!, {r0-r1}
+ mrc p15, 0, r4, c7, c4, 0 @ PAR
+ mrc p15, 0, r5, c10, c2, 0 @ PRRR
+ mrc p15, 0, r6, c10, c2, 1 @ NMRR
+ mrc p15, 0, r7, c12, c0, 0 @ VBAR
+ stmia r9!, {r4-r7}
+
+ mrc p15, 0, r0, c13, c0, 1 @ CONTEXTIDR
+ mrc p15, 0, r1, c13, c0, 2 @ TPIDRURW
+ mrc p15, 0, r2, c13, c0, 3 @ TPIDRURO
+ mrc p15, 0, r3, c13, c0, 4 @ TPIDRPRW
+ stmia r9!, {r0-r3}
+
+ /* to save normal register which including R9,so
+ * use R0 as stack pointer
+ */
+ MOV r0,r9
+
+ /**
+ save 7 modes programmable registers
+ save svc mode registers
+ enter svc mode, no interrupts
+ **/
+
+ MOV r2, #MODE_SVC | I_BIT | F_BIT
+ MSR cpsr_c, r2
+ MRS r1, spsr
+ STMIA r0!, {r1, r13, r14}
+
+ /**
+ save fiq mode registers
+ enter fiq mode, no interrupts
+ **/
+ MOV r2, #MODE_FIQ | I_BIT | F_BIT
+ MSR cpsr_c, r2
+ MRS r1,spsr
+ STMIA r0!, {r1, r8-r14}
+
+ /**
+ save irq mode registers
+ enter irq mode, no interrupts
+ **/
+ MOV r2, #MODE_IRQ | I_BIT | F_BIT
+ MSR cpsr_c, r2
+ MRS r1,spsr
+ STMIA r0!, {r1, r13, r14}
+
+ /**
+ save undefine mode registers
+ enter undefine mode, no interrupts
+ **/
+ MOV r2, #MODE_UND | I_BIT | F_BIT
+ MSR cpsr_c, r2
+ MRS r1,spsr
+ STMIA r0!, {r1, r13, r14}
+
+ /**
+ save abort mode registers
+ enter abort mode, no interrupts
+ **/
+ MOV r2, #MODE_ABT | I_BIT | F_BIT
+ MSR cpsr_c, r2
+ MRS r1,spsr
+ STMIA r0!, {r1, r13, r14}
+
+ /**
+ save system mode registers
+ enter system mode, no interrupts
+ **/
+ MOV r2, #MODE_SYS | I_BIT | F_BIT
+ MSR cpsr_c, r2
+ STMIA r0!, {r13, r14}
+
+ /** back to SVC mode, no interrupts **/
+ MOV r2, #MODE_SVC | I_BIT | F_BIT
+ MSR cpsr_c, r2
+
+ /** save the private timer **/
+save_prv_timer:
+ LDR r4,= A9_PRV_TIMER_BASE
+ LDR r2, [r4, #TIMER_LD] @timer load
+ LDR r3, [r4, #TIMER_CTL] @timer control
+ STMIA r0!, {r2-r3}
+
+ /**
+ Now Master CPU protect the Global timer.
+ save the 64bit timer
+ **/
+ LDR r1,= A9_GLB_TIMER_BASE
+ LDR r2, [r1, #TIM64_CTL] @64-bit timer control
+ BIC r3, r2, #0xF
+ STR r3, [r1, #TIM64_CTL] @disable the features
+
+ /** the registers are now frozen for the context save **/
+ LDR r3, [r1, #TIM64_AUTOINC] @Autoincrement register
+ LDR r4, [r1, #TIM64_CMPLO] @comparator - lo word
+ LDR r5, [r1, #TIM64_CMPHI] @comparator - hi word
+ STMIA r0!, {r2-r5}
+
+ LDR r2, [r1, #TIM64_CNTLO] @counter - lo word
+ LDR r3, [r1, #TIM64_CNTHI] @counter - hi word
+ STMIA r0!, {r2-r3}
+
+
+#ifdef CONFIG_CACHE_L2X0
+ /**
+ save L2CC Configuration
+ **/
+ dsb
+
+ ldr r6, =REG_BASE_L2CC
+ ldr r2, [r6, #L2X0_AUX_CTRL]
+ ldr r3, [r6, #L2X0_TAG_LATENCY_CTRL]
+ ldr r4, [r6, #L2X0_DATA_LATENCY_CTRL]
+ ldr r5, [r6, #L2X0_PREFETCH_OFFSET]
+ stmia r0!, {r2-r5}
+#endif
+ /** save SCU Configruation **/
+ LDR r1,=A9_SCU_BASE
+ LDR r2,[r1,#SCU_FILTER_START_OFFSET]
+ LDR r3,[r1,#SCU_FILTER_END_OFFSET]
+ LDR r4,[r1,#SCU_ACCESS_CONTROL_OFFSET]
+ LDR r5,[r1,#SCU_NONSEC_CONTROL_OFFSET]
+ LDR r6,[r1,#SCU_CONTROL_OFFSET]
+ LDR r7,[r1,#SCU_POWER_STATE_OFFSET]
+ STMIA r0!,{r2-r7}
+
+ /*
+ Protect the NAND Configuration
+ Since it is a risk to read NAND register when
+ we do not konw its clock and reset status
+ so left this work to NAND driver.
+ */
+ /*
+ LDR r4,=NAND_CTRLOR_BASE
+ LDR r1,[r4,#0x0]
+ LDR r2,[r4,#0x10]
+ LDR r3,[r4,#0x14]
+ STMIA r0!,{r1-r3}
+ */
+
+ /**
+ Need not protect the eMMC Configuration
+ eMMC will re enumation
+ **/
+
+SKIP_MASTER_CPU_OPRATORATION:
+
+ str r0,[r8,#SUSPEND_STACK_ADDR] @store the stack_top
+
+ /* Jump to SecuRAM to execute
+ * r6: load return address in r6. But, in normal case, Securam code
+ * will stop in WFI, and never return.
+ *
+ * When system resume, fastboot will jump to (MASTER_SR_BACK_PHY_ADDR)
+ */
+ LDR r7, =(MASTER_SR_BACK_PHY_ADDR)
+ LDR r6, [r7]
+
+ LDR r0, =(REG_BASE_SECRAM)
+ LDR r1, =(DPSLEEP_CODE_ADDR_OFFSET)
+ ADD r0, r0, r1
+ MOV PC, r0 @ Jump to the SECRAM address
+ @ Goto hs_finish_suspend to read the code
+
+/*
+ * Function: master_cpu_resume()
+ *
+ * Resume entry point of Master CPU. Physical address of this function is
+ * stored in MASTER_SR_BACK_PHY_ADDR. During resume, fastboot code fetches
+ * from MASTER_SR_BACK_PHY_ADDR, and jump.
+ *
+ * At the end of this function, it returns to the C world where
+ * hilpm_cpu_godpsleep() is called.
+ */
+ENTRY (master_cpu_resume)
+ /* write domain access to get the domain access right */
+ LDR r0, =0xFFFFFFFF
+ MCR p15, 0, r0, c3, c0, 0
+
+ mov r0, #0
+ mcr p15, 0, r0, c7, c5, 4 @ Flush prefetch buffer
+ mcr p15, 0, r0, c7, c5, 6 @ Invalidate branch predictor array
+ mcr p15, 0, r0, c8, c5, 0 @ Invalidate instruction TLB
+ mcr p15, 0, r0, c8, c6, 0 @ Invalidate data TLB
+
+ mov r10, #0 @ swith back to cache level 0
+ mcr p15, 2, r10, c0, c0, 0 @ select current cache level in cssr
+ dsb
+ isb
+ mov r0, #0
+ mcr p15, 0, r0, c7, c1, 0 @ ICIALLUIS
+ mcr p15, 0, r0, c7, c1, 6 @ BPIALLIS
+ mcr p15, 0, r0, c8, c3, 0
+
+ /**
+ restore_data
+ R10 is reserved to store the PHY address of A9 stored_ctx
+ **/
+ LDR r10, hi_cpu_godpsleep_phybase
+
+ mov r1, #0
+ mcr p15, 0, r1, c7, c5, 0 @ Invalidate entire instruction cache
+ @ and flush branch predictor arrays
+
+master_start_load_ctx:
+
+ /* R0 is reserved to stored_ctx stack pointer */
+ LDR r0, [r10, #SUSPEND_STACK_ADDR]
+
+ /**
+ Resume the NAND Configuration
+ Since it is a risk to read NAND register when
+ we do not konw its clock and reset status
+ so left this work to NAND driver.
+ **/
+ /*
+ LDMDB r0!, {r1-r3}
+ LDR r4,=REG_BASE_NANDC_CFG
+ STR r3,[r4,#0x14]
+ STR r2,[r4,#0x10]
+ STR r1,[r4,#0x0]
+ */
+
+ /* Restore SCU Configruation **/
+ LDMDB r0!, {r2-r7}
+ LDR r1,=A9_SCU_BASE
+ STR r2,[r1,#SCU_FILTER_START_OFFSET]
+ STR r3,[r1,#SCU_FILTER_END_OFFSET]
+ STR r4,[r1,#SCU_ACCESS_CONTROL_OFFSET]
+ STR r5,[r1,#SCU_NONSEC_CONTROL_OFFSET]
+
+ LDR r8, =0xFFFF
+ /* invalidate the duplicate TAG store */
+ STR r8, [r1, #SCU_SEC_INVALID_REG_OFFSET]
+
+ STR r6,[r1,#SCU_CONTROL_OFFSET]
+ STR r7,[r1,#SCU_POWER_STATE_OFFSET] @restore CPU power statue
+
+#ifdef CONFIG_CACHE_L2X0
+ /* restore l2-cache configuration */
+ ldr r6, =REG_BASE_L2CC
+ LDMDB r0!, {r2-r5}
+ str r3, [r6, #L2X0_TAG_LATENCY_CTRL]
+ str r4, [r6, #L2X0_DATA_LATENCY_CTRL]
+ str r5, [r6, #L2X0_PREFETCH_OFFSET]
+ str r2, [r6, #L2X0_AUX_CTRL]
+#endif
+
+ /* restore 64bit global timer */
+ LDR r1, =A9_GLB_TIMER_BASE
+ LDMDB r0!, {r2-r3}
+ STR r2, [r1, #TIM64_CNTLO] @counter - lo word
+ STR r3, [r1, #TIM64_CNTHI] @counter - hi word
+
+ LDMDB r0!, {r2-r5}
+ STR r3, [r1, #TIM64_AUTOINC] @Autoincrement register
+ STR r4, [r1, #TIM64_CMPLO] @comparator - lo word
+ STR r5, [r1, #TIM64_CMPHI] @comparator - hi word
+ STR r2, [r1, #TIM64_CTL] @restore the control last
+
+slave_start_load_ctx:
+ /* restore private timer */
+ LDR r1, =A9_PRV_TIMER_BASE
+ LDMDB r0!, {r2-r3}
+ STR r2, [r1, #TIMER_LD] @timer load
+ STR r3, [r1, #TIMER_CTL] @timer control
+
+ /**
+ resume system mode registers
+ enter system mode, no interrupts
+ **/
+ MOV r2, #MODE_SYS | I_BIT | F_BIT
+ MSR cpsr_c, r2
+ LDMDB r0!, {r13, r14}
+
+ /**
+ resume abort mode registers
+ enter abort mode, no interrupts
+ **/
+ MOV r2, #MODE_ABT | I_BIT | F_BIT
+ MSR cpsr_c, r2
+ LDMDB r0!, {r1, r13, r14}
+ MSR spsr_c, r1
+
+ /**
+ resume undefine mode registers
+ enter undefine mode, no interrupts
+ **/
+ MOV r2, #MODE_UND | I_BIT | F_BIT
+ MSR cpsr_c, r2
+ LDMDB r0!, {r1, r13, r14}
+ MSR spsr_c, r1
+
+ /**
+ resume irq mode registers
+ enter irq mode, no interrupts
+ **/
+ MOV r2, #MODE_IRQ | I_BIT | F_BIT
+ MSR cpsr_c, r2
+ LDMDB r0!, {r1, r13, r14}
+ MSR spsr_c, r1
+
+ /**
+ resume fiq mode registers
+ enter fiq mode, no interrupts
+ **/
+ MOV r2, #MODE_FIQ | I_BIT | F_BIT
+ MSR cpsr_c, r2
+ LDMDB r0!, {r1, r8-r14}
+ MSR spsr_c, r1
+
+ /**
+ resume svc mode registers
+ enter svc mode, no interrupts
+ **/
+ MOV r2, #MODE_SVC | I_BIT | F_BIT
+ MSR cpsr_c, r2
+ LDMDB r0!, {r1, r13, r14}
+ MSR spsr_c, r1
+
+ /* Restore CP15 register, need use r0 register
+ * use R8 replace R0 to save Stack_pointer
+ */
+ MOV r8,r0
+
+
+ /** restore CP15 register **/
+ LDMDB r8!, {r0-r3}
+ mcr p15, 0, r0, c13, c0, 1 @ CONTEXTIDR
+ mcr p15, 0, r1, c13, c0, 2 @ TPIDRURW
+ mcr p15, 0, r2, c13, c0, 3 @ TPIDRURO
+ mcr p15, 0, r3, c13, c0, 4 @ TPIDRPRW
+
+ LDMDB r8!, {r4-r7}
+ mcr p15, 0, r4, c7, c4, 0 @ PAR
+ mcr p15, 0, r5, c10, c2, 0 @ PRRR
+ mcr p15, 0, r6, c10, c2, 1 @ NMRR
+ mcr p15, 0, r7, c12, c0, 0 @ VBAR
+
+ LDMDB r8!, {r0,r1}
+ mcr p15, 0, r0, c15, c0, 1 @ diag
+ mcr p15, 0, r1, c1, c0, 2 @ cpacr
+
+ LDMDB r8!, {r0, r4}
+ mcr p15, 2, r0, c0, c0, 0 @ csselr
+ mcr p15, 0, r4, c15, c0, 0 @ pctlr
+
+ /* Invalid L1-Cache */
+ mov r3,#0x0
+ mcr p15, 2, r3, c0, c0, 0 @ select L1 Data-cache
+ mrc p15, 1, r3, c0, c0, 0 @ Read Current Cache Size-
+ @ Identification Register
+
+ ldr r1,=0x1ff
+ and r3, r1, r3, LSR #13 @r3 = number of sets in cache
+ mov r0,#0x0
+way_loop:
+ mov r1, #0x0 @r1 -> set counter
+set_loop:
+ mov r2, r0, LSL #30
+ orr r2, r1, LSL #5 @r2->set/way cache-op format
+ mcr p15, 0, r2, c7, c6, 2 @Invalid Line descript by r2
+ add r1, r1, #1 @increment set counter
+
+ cmp r1, r3 @check if last set is reached...
+ ble set_loop @if not continue set_loop
+ add r0,r0, #1 @else increment way counter
+
+ cmp r0,#4 @check if last way is reached
+ blt way_loop @if not,continue way_loop
+
+ /**
+ now restore the critial P15 register
+ restore critial P15 register before MMU Enabled
+ save CTRL_Register in r0
+ save Aux_Ctrl_register in r1
+ TTBR0 in r2
+ TTBR1 in r3
+ TTBCR in r4
+ DAC in R5
+ **/
+
+ ADD r10,r10,#0x4
+
+ LDMIA r10, {r0-r5, r7-r9}
+
+ MCR p15, 0, r2, c2, c0, 0 @ TTBR0
+ MCR p15, 0, r3, c2, c0, 1 @ TTBR1
+ MCR p15, 0, r4, c2, c0, 2 @ TTBCR
+
+ /**
+ r0 store the Stored Control register value
+ **/
+ MCR p15, 0, r0, c1, c0, 0 @ turn on MMU, I-cache, etc
+ instr_sync
+ mov pc, r9
+
+mmu_enalbed:
+ str r7, [r8]
+
+ mcr p15, 0, r1, c1, c0, 1 @ actlr
+ mcr p15, 0, r5, c3, c0, 0 @ domain access control reg
+
+#ifdef CONFIG_CPU_IDLE
+#error hilpm_cp_cpuidle_code() not defined
+@ bl hilpm_cp_cpuidle_code
+#endif
+
+ LDMFD sp!, {r4-r11, pc}
+ENDPROC (master_cpu_resume)
+
+
+/* Function: hs_finish_suspend()
+ *
+ * This code is copied to Securam for execution, because DDR is set to
+ * self-refresh mode. Here, final steps before setting master CPU to
+ * deepsleep are included.
+ *
+ * After WFI, master CPU enters deepsleep. All codes after WFI is not
+ * executed. When master CPU is waken up, master_cpu_resume() will be
+ * called. Please read description there.
+ */
+ .align 3
+ENTRY (hs_finish_suspend)
+ instr_sync
+ /**
+ STEP1: Protect the DDR Train Address and Traning Data into Syscontrol
+ We need not do it, it will be config in fastboot
+ **/
+
+ /**
+ config DDR enter self-refresh state
+ **/
+ LDR r0, =DDR_CTRLOR_BASE
+ LDR r1, =0x01
+ STR r1, [r0,#0x4]
+
+ /* check DDR self-fresh status */
+CheckDDREnterSF:
+ LDR r1, [r0, #0x0]
+ TST r1, #0x04
+ BEQ CheckDDREnterSF
+
+ /**
+ config DDR PHY enter CKE-Retention status
+ fastboot code will do opposition relevent operations.
+ **/
+ LDR r4,=REG_BASE_SCTRL
+ LDR r1,[r4,#0x20C] @SCTRL SCPERCTRL3 register
+ ORR r1,r1,#0x3 @set sc_ddr_ret_en bit[1:0] to 0x3
+ STR r1,[r4,#0x20C]
+
+ /**
+ Set MDDRC's clock to DDRPHY's input clock
+ fastboot code will do opposition relevent operations.
+ **/
+ LDR r4,=REG_BASE_PMCTRL
+ LDR r1,=0x0
+ STR r1,[r4,#0xA8] @DDRCLKSEL
+
+r_wait_mddrc_clk:
+ LDR r1,[r4,#0xA8]
+ TST r1,#0x2
+ BNE r_wait_mddrc_clk
+
+ /*set ddr clk div*/ @360M
+ LDR r1, = 0x03
+ STR r1, [r4, #0x0AC]
+r_waite_mddr_div:
+ LDR r1, [r4, #0x0AC]
+ TST r1, #0x20
+ BEQ r_waite_mddr_div
+
+ /*ddr clk change to peri PLL*/
+ MOV r2, #0x0
+ LDR r1, =0x00
+ STR r1, [r4, #0x030]
+r_wait_ddrcclk_sw:
+ ADD r2, r2, #0x1
+ CMP r2, #0x1000
+ BEQ r_wait_ddrcclk_ok
+ LDR r1, [r4, #0x30]
+ CMP r1, #0x00
+ BNE r_wait_ddrcclk_sw
+
+r_wait_ddrcclk_ok:
+
+ /*close GPU PLL*/
+ LDR r1, =0x00
+ STR r1, [r4, #0x028]
+
+ /**
+ Close LD03
+ **/
+
+ /*enable pmuspi*/
+ /*pmuspi clk div 4*/
+ LDR r1, =REG_BASE_PCTRL
+ LDR r4, =0xFF0003
+ STR r4, [r1, #0x8]
+
+ /*enable clk*/
+ LDR r1, =REG_BASE_SCTRL
+ LDR r4, =0x2
+ STR r4, [r1, #0x40]
+
+ /*undo reset*/
+ LDR r4, =0x2
+ STR r4, [r1, #0x9C]
+
+ /*close LDO3*/
+ LDR r1, =REG_BASE_PMUSPI
+ LDR r4, [r1, #0x8C]
+ BIC r4, #0x10
+ STR r4, [r1, #0x8C]
+
+ /*disable pmuspi*/
+ /*reset*/
+ LDR r1, =REG_BASE_SCTRL
+ LDR r4, =0x2
+ STR r4, [r1, #0x98]
+
+ /*disable clk*/
+ LDR r4, =0x2
+ STR r4, [r1, #0x44]
+
+
+ /**
+ STEP2. Clear intr response mode status register
+ Try clear intr response mode status first
+ if the status is cleared, means there has no
+ intr pending, go dpsleep, else do not configuration
+ any dpsleep register and go back
+ **/
+ LDR r4,=REG_BASE_SCTRL
+ LDR r1,=0x0
+ STR r1,[r4,#0xc] @clear intr status register
+ NOP
+ NOP
+ /* check if we are still in intr response status */
+ /* 2012-2-14 do not care about wakeup intr*/
+ @LDR r1,[r4,#0xc]
+ @TST r1,#0x01
+ @BNE Back_from_WFI @go directly to Resume
+
+ /* exit intr response mode */
+ LDR r2,[r4,#8]
+ BIC r2,#1
+ STR r2,[r4,#8]
+
+ /**
+ STEP3 Protect EMMC/NAND Component IO, config WP to LOW CLOSE eMMC/NAND Component LDO
+ NOW EMMC/NAND Driver do the protection operation, we do nothing here
+ **/
+
+ /**
+ STEP4 config dpsleep register
+ **/
+ LDR r4,=REG_BASE_SCTRL
+ LDR r1,[r4]
+ LDR r2,=0x01000007 @BIT24: Enable DpSleep Mode, BIT2|BIT1|BIT0 = 7
+ BIC r1,r1,r2 @clear first
+ LDR r2,=0x01000000 @BIT24: Enable DpSleep Mod=1,
+ @modctrl(BIT2|BIT1|BIT0) = 000 (Sleep)
+ ORR r1,r1,r2 @Enable DpSleep Mode,ModeCtrl=sleep
+ STR r1,[r4]
+
+ /* STEP5 CHIP required, config L2CC for LOWPOWER */
+ LDR r4,=REG_BASE_L2CC
+ LDR r2,[r4,#0xF80]
+ ORR r1,r2,#0x1
+ STR r1,[r4,#0xF80]
+
+ /**
+ STEP6. CHIP required, configure SCU power status register
+ cause if we back from wfi, scu power status must be
+ restore back, we protect the data into r11
+ **/
+ LDR r4,=REG_BASE_A9PER
+ LDR r11,[r4,#0x08] @protect the SCU power status to r11
+ LDR r1,=0x03030303 @all CPU to Power-off Mode
+ STR r1,[r4,#0x08]
+
+ /**
+ STEP7. configure SCU Standby EN
+ CAUSTION: this configuration suggest to be set before the whole
+ system start
+ **/
+ LDR R4,=REG_BASE_A9PER
+ LDR r1,[r4]
+ ORR r1,r1,#0x20
+ STR r1,[r4]
+
+ /**
+ STEP9 to enable ACP''s clock as a must for SCUIDLE
+ **/
+ LDR R4, =REG_BASE_SCTRL
+ MOV R1, #0x10000000 @BIT28 for ACP clock enable control
+ STR R1, [R4,#0x30] @Register SCPEREN1
+
+
+ /**
+ STEP10 clear ScuRAM Ready FLAG,please refer to OnChipROM Design
+ FIXME: the FLAG also including the optional information
+ (Refer to OnChipROM design)
+ **/
+ LDR r4,=SECURAM_CODE_READY_FLAG
+ LDR r1,=0x0
+ STR r1,[r4,#0x0]
+
+ /**
+ STEP11 Enter WFI
+ **/
+ DSB
+ WFI
+
+ NOP
+ NOP
+ NOP
+ NOP
+
+Back_from_WFI:
+ /**
+ We are draged back from an interrupt
+ Caustion: R6 is reserved to store the go-back PHY address
+
+ STEP1: Restore the IO/LDO Configuration of EMMC/NAND Component
+ WE DO Nothing here
+ **/
+
+ /* STEP2: Restore the Securam_CODE_READY FLAG.
+ * Refer to OnChipROM Design
+ */
+ LDR r4,=SECURAM_CODE_READY_FLAG
+ LDR r1,[r4]
+ LDR r2,=0xFFFF
+ BIC r1,r1,r2
+ LDR r2,=0xBEEF @0xBEEF is the SECURAM_CODE_READY_FLAG
+ ORR r1,r1,r2
+ STR r1,[r4,#0x0]
+
+ /**
+ STEP3: make Sure system in Normal state
+ if system in SLOW mode, configuration to NORMAL mode
+ FIXME: Coding here if needed
+ **/
+ LDR r2, =REG_BASE_SCTRL
+ LDR r1, [r2]
+ AND r4, r1, #0x4
+ CMP r4, #0x4
+ BEQ cpunormal
+ ORR r1, r1, #0x4
+ STR r1, [r2]
+normalwait:
+ LDR r1, [r2]
+ AND r1, r1, #0x78
+ CMP r1, #0x20
+ BNE normalwait
+
+cpunormal:
+
+ /**
+ STEP4: Restore DDR Configuration to Normal
+ Restore DDR PHY CLK, exit CKE-Retention mode
+ **/
+
+ /** change DDR PHY CLK to output mode **/
+ /**
+ FIXME: Remove the comments when fastboot add the
+ relevent operations.
+ **/
+ LDR r4,=REG_BASE_PMCTRL
+ LDR r1,=0x1
+ STR r1,[r4,#0xA8] @DDRCLKSEL
+
+ /** exit CKE retention mode **/
+ LDR r4,=REG_BASE_SCTRL
+ LDR r1,[r4,#0x20C] @SCTRL SCPERCTRL3 register
+ BIC r1,r1,#0x3 @set sc_ddr_ret_en bit[1:0] to 0x0
+ STR r1,[r4,#0x20C]
+
+ /**
+ Open LD03
+ **/
+
+ /*enable pmuspi*/
+ /*pmuspi clk div 4*/
+ LDR r1, =REG_BASE_PCTRL
+ LDR r4, =0xFF0003
+ STR r4, [r1, #0x8]
+
+ /*enable clk*/
+ LDR r1, =REG_BASE_SCTRL
+ LDR r4, =0x2
+ STR r4, [r1, #0x40]
+
+ /*undo reset*/
+ LDR r4, =0x2
+ STR r4, [r1, #0x9C]
+
+ /*open LDO3*/
+ LDR r1, =REG_BASE_PMUSPI
+ LDR r4, [r1, #0x8C]
+ ORR r4, #0x10
+ STR r4, [r1, #0x8C]
+
+ /*disable pmuspi*/
+ /*reset*/
+ /*LDR r1, =REG_BASE_SCTRL*/
+ /*LDR r4, =0x2*/
+ /*STR r4, [r1, #0x98]*/
+
+ /*disable clk*/
+ /*LDR r4, =0x2*/
+ /*STR r4, [r1, #0x44]*/
+
+ /*about 100ms*/
+ LDR r4, =0x2625A00
+ldo3delay:
+ SUBS r4, r4, #0x1
+ BNE ldo3delay
+
+ /** Config DDR leave self-refresh mode **/
+ LDR r0,=DDR_CTRLOR_BASE
+ LDR r1,=0x00
+ STR r1,[r0,#0x4]
+
+ /** check DDR self-refresh status **/
+CheckDDRLeaveSF:
+ LDR r1, [r0, #0x0]
+ TST r1, #0x04
+ BNE CheckDDRLeaveSF
+
+ /** STEP5 restore SCU CPU power states, which restore in r11 before **/
+ LDR r4,=REG_BASE_A9PER
+ STR r11,[r4,#0x08] @restore the SCU power status from r11
+
+ /** STEP6 go Back to DDR Address Store in R6 **/
+ MOV pc, r6
+
+ENDPROC (hs_finish_suspend)
+
+ .ltorg
+
+.global hi_cpu_godpsleep_ddrbase
+hi_cpu_godpsleep_ddrbase:
+ .word hi_cpu_godpsleep_ddrbase
+
+.global hi_cpu_godpsleep_phybase
+hi_cpu_godpsleep_phybase:
+ .word hi_cpu_godpsleep_phybase
diff --git a/arch/arm/mach-hs/hipm.h b/arch/arm/mach-hs/hipm.h
new file mode 100644
index 000000000000..db7059622da7
--- /dev/null
+++ b/arch/arm/mach-hs/hipm.h
@@ -0,0 +1,183 @@
+/*
+ * Header for power management related routines
+ *
+ * Copyright © 2011-2013 HiSilicon Technologies Co., Ltd.
+ * http://www.hisilicon.com
+ * Copyright © 2012-2013 Linaro Ltd.
+ * http://www.linaro.org
+ *
+ * Author: Guodong Xu <guodong.xu@linaro.org>
+ *
+ * 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.
+ *
+ */
+#ifndef __MACH_HS_HIPM_H
+#define __MACH_HS_HIPM_H
+
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <asm/pgtable.h>
+
+/* Physical DRAM offset */
+#define K3_PLAT_PHYS_OFFSET UL(0x40000000)
+
+#define SR_PROTECT_CTX_BUFF_SIZE (2048)
+#define PMU_HRST_REG (hs_pmuspi_va_base + (0x87 << 2))
+
+#define REG_BASE_SECRAM (0xF8000000)
+#define REG_BASE_L2CC (0xFC100000)
+#define REG_BASE_A9PER (0xFC000000)
+#define REG_BASE_DDRC_CFG (0xFCD00000)
+#define REG_BASE_SCTRL (0xFC802000)
+#define REG_BASE_PMCTRL (0xFCA08000)
+#define REG_BASE_PCTRL (0xFCA09000)
+#define REG_BASE_PMUSPI (0xFCC00000)
+
+/* Define A9 Cluster Address */
+#define A9_SCU_BASE REG_BASE_A9PER
+#define A9_PRV_TIMER_BASE (REG_BASE_A9PER + 0x600)
+#define A9_GLB_TIMER_BASE (REG_BASE_A9PER + 0x200)
+
+#define DDR_CTRLOR_BASE (REG_BASE_DDRC_CFG)
+#define NAND_CTRLOR_BASE (REG_BASE_NANDC_CFG)
+
+/* OFFSETs based off SYSCTRL */
+/* MASTER_SR_BACK_PHY_ADDR Store the restore address of CPU0
+ */
+#define MASTER_SR_BACK_PHY_ADDR (REG_BASE_SCTRL + 0x308)
+
+/************************************************************
+ SecuRAM Useage Map During Suspend/Resume
+
+
++---------------------------+ 0xF8000000
+| | Boot-Code(Support S/R operation)
+| 2K Bytes | Including Function:
+| | DISMMU_IN_SECURAM,
+| | ENMMU_IN_SECURAM
++---------------------------+ 0xF8000800
+| 32 Bytes | Prestore area of CTRL_Register/
+| | Aux_Ctrl_register/
+| | TTBR0/TTBR1/TTBCR/DAC of CPU0
++---------------------------+ 0xF8000820
+| 32 Bytes | Prestore area of CTRL_Register/
+| | Aux_Ctrl_register/
+| | TTBR0/TTBR1/TTBCR/DAC of CPU1
++---------------------------+ 0xF8000840
+| 32 Bytes | Prestore area of CTRL_Register/
+| | Aux_Ctrl_register/
+| | TTBR0/TTBR1/TTBCR/DAC of CPU2
++---------------------------+ 0xF8000860
+| 32 Bytes | Prestore area of CTRL_Register/
+| | Aux_Ctrl_register/
+| | TTBR0/TTBR1/TTBCR/DAC of CPU3
++---------------------------+ 0xF8000880
+| |
++---------------------------+ 0xF8000900
+| 64 Bytes | Store disable_mmu assembly code
++---------------------------+ 0xF8000940
+| 64 Bytes | Store the enable_mmu assembly code
++---------------------------+ 0xF8000980
+| 128 Bytes | Slave CPU entry code
+| |
++---------------------------+ 0xF8000A00
+| DeepSleep Code |
+| 1K Bytes | Code to make DDR enter
+| | self-refresh, and
+| | configure the SYSCTRL to
+| | make system enter deepsleep
++---------------------------+ 0xF8000E00
+| |
+|~~ ~~ ~~ ~~ ~~ ~~ ~~ |
+ ~~ ~~ ~~ ~~ ~~ ~~ ~
+
+A9_PRE_STORE_DATA_ADDR: the Address in Securam,
+A9_PRE_STORE_DATA_LEN: the data length of each A9
+DPSLEEP_CODE_ADDR: the address of DeepSleep Code
+DPSLEEP_CODE_LEN: the len of DeepSleep Code
+
+******************************************************************/
+
+/* Disable/Enable MMU FUNCTION ADDRESS */
+#define DISMMU_CODE_IN_SECURAM (REG_BASE_SECRAM+0x900)
+#define ENMMU_CODE_IN_SECURAM (REG_BASE_SECRAM+0x940)
+#define SECURAM_CODE_LEN (0x40)
+
+/* OFFSETs based off SECRAM */
+#define SLAVE_CPU_ENTRY_CODE_ADDR (REG_BASE_SECRAM + 0x980)
+#define SLAVE_CPU_ENTRY_CODE_LEN (0x80)
+#define A9_PRE_STORE_DATA_ADDR_OFFSET (0x800)
+#define A9_PRE_STORE_DATA_LEN (32)
+#define DPSLEEP_CODE_ADDR_OFFSET (0xA00)
+#define DPSLEEP_CODE_LEN (0x400)
+
+#define SECURAM_CODE_READY_FLAG (REG_BASE_SCTRL+0x330)
+
+/* SUSPEND_STORE_OFFSET_UNIT define
+ the Data-Length of DDR area to save
+ A9 context */
+#define SUSPEND_STORE_OFFSET_UNIT (0x200)
+#define SUSPEND_STORE_RESEVED_UNIT (0x30)
+#define SUSPEND_STACK_ADDR (SUSPEND_STORE_RESEVED_UNIT - 0x4)
+
+
+#define SCU_CONTROL_OFFSET (0x00)
+#define SCU_CONFIG_OFFSET (0x04)
+#define SCU_POWER_STATE_OFFSET (0x08)
+#define SCU_SEC_INVALID_REG_OFFSET (0x0c)
+#define SCU_FILTER_START_OFFSET (0x40)
+#define SCU_FILTER_END_OFFSET (0x44)
+#define SCU_ACCESS_CONTROL_OFFSET (0x50)
+#define SCU_NONSEC_CONTROL_OFFSET (0x54)
+
+#define L2X0_AUX_CTRL 0x104
+#define L2X0_TAG_LATENCY_CTRL 0x108
+#define L2X0_DATA_LATENCY_CTRL 0x10C
+#define L2X0_PREFETCH_OFFSET 0xF60
+
+#define TIMER_LD (0x0)
+#define TIMER_CTL (0x8)
+
+#define TIM64_CNTLO (0x0)
+#define TIM64_CNTHI (0x4)
+#define TIM64_CTL (0x8)
+#define TIM64_CMPLO (0x10)
+#define TIM64_CMPHI (0x14)
+#define TIM64_AUTOINC (0x18)
+
+/* General CPU constants */
+#define MODE_FIQ (0x11)
+#define MODE_IRQ (0x12)
+#define MODE_SVC (0x13)
+#define MODE_ABT (0x17)
+#define MODE_UND (0x1B)
+#define MODE_SYS (0x1F)
+#define I_BIT (0x80)
+#define F_BIT (0x40)
+
+#define TTBRBIT_MASK 0xFFFFC000
+#define TABLE_INDEX_MASK 0xFFF00000
+#define TABLE_ENTRY 0x00000C02
+
+#define hisi_v2p(x) ((x) - PAGE_OFFSET + K3_PLAT_PHYS_OFFSET)
+#define hisi_p2v(x) ((x) - K3_PLAT_PHYS_OFFSET + PAGE_OFFSET)
+
+/* TCXO stable time configuation */
+#define SCXTALCTRL_CFG_VAL_005MS (0x1FFFF5D0) /*5ms*/
+#define SCXTALCTRL_CFG_VAL_200MS (0x1FFE6660) /*200ms*/
+
+#ifndef __ASSEMBLY__
+extern asmlinkage void __iomem *hs_finish_suspend(void);
+extern asmlinkage void __iomem *master_cpu_resume(void);
+extern asmlinkage void __iomem *get_ttbr0(void);
+extern asmlinkage void hilpm_cpu_godpsleep(void);
+extern asmlinkage void hilpm_cp_securam_code(void __iomem *);
+extern asmlinkage void hilpm_cp_cpuidle_code(void);
+extern unsigned long hi_cpu_godpsleep_ddrbase;
+extern unsigned long hi_cpu_godpsleep_phybase;
+#endif
+
+#endif /* #ifndef __MACH_HS_HIPM_H */
diff --git a/arch/arm/mach-hs/hotplug.c b/arch/arm/mach-hs/hotplug.c
new file mode 100644
index 000000000000..c67f8a22a890
--- /dev/null
+++ b/arch/arm/mach-hs/hotplug.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2013 Linaro Ltd.
+ * Copyright (c) 2013 Hisilicon Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+#include <linux/cpu.h>
+#include <linux/io.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <asm/cacheflush.h>
+#include <asm/smp_plat.h>
+#include "core.h"
+
+enum {
+ HI3620_CTRL,
+ HI3716_CTRL,
+};
+
+static void __iomem *ctrl_base;
+static int id;
+
+void hs_set_cpu(int cpu, bool enable)
+{
+ u32 val = 0;
+
+ if (!ctrl_base)
+ return;
+
+ if (id == HI3620_CTRL) {
+ if (enable) {
+ /* MTCMOS */
+ writel_relaxed((0x01 << (cpu + 3)), ctrl_base + 0xD0);
+ writel_relaxed((0x1011 << cpu), ctrl_base + 0x414);
+ writel_relaxed((0x401011 << cpu), ctrl_base + 0x410);
+
+ /* ISO disable */
+ writel((0x01 << (cpu + 3)), ctrl_base + 0x0C4);
+
+ /* WFI Mask */
+ val = readl(ctrl_base + 0x200);
+ val &= ~(0x1 << (cpu+28));
+ writel(val, ctrl_base + 0x200);
+
+ /* Enable core */
+ writel_relaxed((0x01 << cpu), ctrl_base + 0xf4);
+ /* Unreset */
+ writel_relaxed((0x401011 << cpu), ctrl_base + 0x414);
+ } else {
+ /* iso enable */
+ writel_relaxed((0x01 << (cpu + 3)), ctrl_base + 0xC0);
+
+ /* MTCMOS */
+ writel_relaxed((0x01 << (cpu + 3)), ctrl_base + 0xD4);
+
+ /* wfi mask */
+ val = readl_relaxed(ctrl_base + 0x200);
+ val |= (0x1 << (cpu+28));
+ writel_relaxed(val, ctrl_base + 0x200);
+
+ /* disable core*/
+ writel_relaxed((0x01 << cpu), ctrl_base + 0xf8);
+ /* Reset */
+ writel_relaxed((0x401011 << cpu), ctrl_base + 0x410);
+ }
+ } else if (id == HI3716_CTRL) {
+ if (enable) {
+ /* power on cpu1 */
+ val = readl_relaxed(ctrl_base + 0x1000);
+ val &= ~(0x1 << 8);
+ val |= (0x1 << 7);
+ val &= ~(0x1 << 3);
+ writel_relaxed(val, ctrl_base + 0x1000);
+
+ /* unreset */
+ val = readl_relaxed(ctrl_base + 0x50);
+ val &= ~(0x1 << 17);
+ writel_relaxed(val, ctrl_base + 0x50);
+ } else {
+ /* power down cpu1 */
+ val = readl_relaxed(ctrl_base + 0x1000);
+ val &= ~(0x1 << 8);
+ val |= (0x1 << 7);
+ val |= (0x1 << 3);
+ writel_relaxed(val, ctrl_base + 0x1000);
+
+ /* reset */
+ val = readl_relaxed(ctrl_base + 0x50);
+ val |= (0x1 << 17);
+ writel_relaxed(val, ctrl_base + 0x50);
+ }
+ }
+}
+
+void __init hs_hotplug_init(void)
+{
+ struct device_node *node;
+
+ node = of_find_compatible_node(NULL, NULL, "hisilicon,cpuctrl");
+ if (node) {
+ ctrl_base = of_iomap(node, 0);
+ id = HI3716_CTRL;
+ return;
+ }
+ node = of_find_compatible_node(NULL, NULL, "hisilicon,sctrl");
+ if (node) {
+ ctrl_base = of_iomap(node, 0);
+ id = HI3620_CTRL;
+ return;
+ }
+}
+
+static inline void cpu_enter_lowpower(void)
+{
+ unsigned int v;
+
+ flush_cache_all();
+ asm volatile(
+ /*
+ * Turn off coherency and L1 D-cache
+ */
+ " mrc p15, 0, %0, c1, c0, 1\n"
+ " bic %0, %0, #0x40\n"
+ " mcr p15, 0, %0, c1, c0, 1\n"
+ " mrc p15, 0, %0, c1, c0, 0\n"
+ " bic %0, %0, #0x04\n"
+ " mcr p15, 0, %0, c1, c0, 0\n"
+ : "=&r" (v)
+ : "r" (0)
+ : "cc");
+}
+
+void hs_cpu_die(unsigned int cpu)
+{
+ cpu_enter_lowpower();
+ hs_set_cpu_jump(cpu, phys_to_virt(0));
+ cpu_do_idle();
+
+ /* We should have never returned from idle */
+ panic("cpu %d unexpectedly exit from shutdown\n", cpu);
+}
+
+int hs_cpu_kill(unsigned int cpu)
+{
+ unsigned long timeout = jiffies + msecs_to_jiffies(50);
+
+ while (hs_get_cpu_jump(cpu))
+ if (time_after(jiffies, timeout))
+ return 0;
+ hs_set_cpu(cpu, false);
+ return 1;
+}
diff --git a/arch/arm/mach-hs/hs-dt.c b/arch/arm/mach-hs/hs-dt.c
new file mode 100644
index 000000000000..774ace66cc22
--- /dev/null
+++ b/arch/arm/mach-hs/hs-dt.c
@@ -0,0 +1,82 @@
+/*
+ * (Hisilicon's Hi36xx/Hi37xx SoC based) flattened device tree enabled machine
+ *
+ * Copyright (c) 2012-2013 Linaro Ltd.
+ *
+ * Haojian Zhuang <haojian.zhuang@linaro.org>
+ *
+ * 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/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/irqchip.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+
+#include <asm/hardware/arm_timer.h>
+#include <asm/hardware/cache-l2x0.h>
+#include <asm/hardware/timer-sp.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/time.h>
+
+#include <linux/clocksource.h>
+#include "core.h"
+
+static struct of_device_id hs_l2cache_match[] __initdata = {
+ { .compatible = "arm,pl310-cache", },
+ {}
+};
+
+static void __init hi3xxx_timer_init(void)
+{
+ struct device_node *node = NULL;
+ int ret;
+ u32 data[2];
+
+ hs_map_io();
+ hs_hotplug_init();
+ of_clk_init(NULL);
+ clocksource_of_init();
+
+ node = of_find_matching_node(NULL, hs_l2cache_match);
+ WARN_ON(!node);
+ if (!node) {
+ pr_err("Failed to find l2cache\n");
+ return;
+ }
+ ret = of_property_read_u32_array(node, "hisilicon,l2cache-aux",
+ &data[0], 2);
+ if (ret < 0) {
+ data[0] = 0;
+ data[1] = ~0UL;
+ }
+ l2x0_of_init(data[0], data[1]);
+}
+
+static void __init hs_init(void)
+{
+ of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+}
+
+static const char *hs_compat[] __initdata = {
+ "hisilicon,hi3620-hi4511",
+ "hisilicon,hi3716",
+ NULL,
+};
+
+DT_MACHINE_START(HS_DT, "Hisilicon Hi36xx/Hi37xx (Flattened Device Tree)")
+ /* Maintainer: Haojian Zhuang <haojian.zhuang@linaro.org> */
+ .map_io = debug_ll_io_init,
+ .init_irq = irqchip_init,
+ .init_time = hi3xxx_timer_init,
+ .init_machine = hs_init,
+ .dt_compat = hs_compat,
+ .smp = smp_ops(hs_smp_ops),
+ .restart = hs_restart,
+MACHINE_END
diff --git a/arch/arm/mach-hs/lowpmregs.c b/arch/arm/mach-hs/lowpmregs.c
new file mode 100644
index 000000000000..d1c84edcc57e
--- /dev/null
+++ b/arch/arm/mach-hs/lowpmregs.c
@@ -0,0 +1,150 @@
+/*
+ * Routines for PMU/Hi6421 suspend/resume. Hi4511 board specific.
+ *
+ * Copyright © 2011-2013 HiSilicon Technologies Co., Ltd.
+ * http://www.hisilicon.com
+ * Copyright © 2012-2013 Linaro Ltd.
+ * http://www.linaro.org
+ *
+ * Author: Guodong Xu <guodong.xu@linaro.org>
+ *
+ * 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.
+ *
+ * Note: Routines defined in this file is for Hi4511 board specific, and will be
+ * called during system suspend to RAM. It should be finally moved to Hi6421
+ * driver's pm routines.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/console.h>
+#include <asm/hardware/arm_timer.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include "core.h"
+
+/* function: pmuspi_enable
+ * description:
+ * enable pmu clk.
+ */
+static void pmuspi_enable(void)
+{
+ /*set clk div*/
+ writel(0xFF0003, (hs_pctrl_va_base + 0x8));
+
+ /*enable clk*/
+ writel(1<<1, (hs_sctrl_base + 0x40));
+
+ /*undo reset*/
+ writel(1<<1, (hs_sctrl_base + 0x9C));
+}
+
+/* function: pmuspi_disable
+ * description:
+ * disable pmu clk.
+ */
+static void pmuspi_disable(void)
+{
+ /*reset*/
+ writel(1<<1, (hs_sctrl_base + 0x98));
+
+ /*disable clk*/
+ writel(1<<1, (hs_sctrl_base + 0x44));
+}
+
+#define PMUSPI_REG(x) (hs_pmuspi_va_base + ((x)<<2))
+
+struct pmuregs {
+ unsigned char ucoffset;
+ char cval;
+ char old_val;
+ char cmask;
+};
+
+#define PMU_LOW(x, y, z) { .ucoffset = (x),\
+ .cval = (y), \
+ .cmask = (z), \
+ .old_val = 0, \
+ }
+
+static struct pmuregs pmuregs_lookups[] = {
+ /*close LDO0 */
+ PMU_LOW(0x20, 0x00, 0x10),
+
+ /*w 35 0, emmc rst2_n output low.*/
+ PMU_LOW(0x35, 0x00, 0x01),
+
+ /*close ldo13*/
+ PMU_LOW(0x2D, 0x30, 0x30),
+
+ /*w 25 31 LDO5 ECO mode*/
+ /*PMU_LOW(0x25, 0x20, 0x20),*/
+
+ /*w 26 34 LDO6 ECO mode*/
+ /*PMU_LOW(0x26, 0x20, 0x20),*/
+
+ /*w 4e 20 close over temperature protect*/
+ PMU_LOW(0x4E, 0x00, 0x01),
+
+ /*w 52 00 close backup battery charging*/
+ PMU_LOW(0x52, 0x00, 0x01),
+
+ /*w 14 11 BUCK4 Sleep*/
+ PMU_LOW(0x14, 0x11, 0x11),
+
+ /*w 16 11 BUCK5 Sleep*/
+ PMU_LOW(0x16, 0x11, 0x11),
+
+ /*w 8f 08 sleep*/
+ /*PMU_LOW(0x8F, 0x08, 0x07),*/
+};
+
+
+/* function: pmulowpower
+ * description:
+ * configure pmu low power state.
+ */
+void pmulowpower(int isuspend)
+{
+ int i = 0;
+ int ilen = ARRAY_SIZE(pmuregs_lookups);
+ unsigned uregv = 0;
+
+ pr_info("[%s] %d enter.\n", __func__, __LINE__);
+
+ pmuspi_enable();
+
+ if (1 == isuspend) {
+ for (i = 0; i < ilen; i++) {
+ uregv = readl(PMUSPI_REG(pmuregs_lookups[i].ucoffset));
+ pmuregs_lookups[i].old_val = uregv;
+ uregv &= ~pmuregs_lookups[i].cmask;
+ uregv |= pmuregs_lookups[i].cval;
+ writel(uregv, PMUSPI_REG(pmuregs_lookups[i].ucoffset));
+ }
+ } else {
+ for (i = (ilen - 1); i >= 0; i--) {
+ uregv = readl(PMUSPI_REG(pmuregs_lookups[i].ucoffset));
+ uregv &= ~pmuregs_lookups[i].cmask;
+ uregv |= pmuregs_lookups[i].old_val;
+ writel(uregv, PMUSPI_REG(pmuregs_lookups[i].ucoffset));
+ }
+ }
+
+ if (1 == isuspend) {
+ pmuspi_disable();
+ /* here is an workround way to delay 40ms
+ * make sure LDO0 is poweroff very clean
+ */
+ mdelay(40);
+ }
+}
diff --git a/arch/arm/mach-hs/platsmp.c b/arch/arm/mach-hs/platsmp.c
new file mode 100644
index 000000000000..6a086307abbf
--- /dev/null
+++ b/arch/arm/mach-hs/platsmp.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2013 Linaro Ltd.
+ * Copyright (c) 2013 Hisilicon Limited.
+ * Based on platsmp.c, Copyright (C) 2002 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+#include <linux/smp.h>
+#include <linux/io.h>
+#include <asm/smp_scu.h>
+
+#include "core.h"
+
+static void __init hs_smp_prepare_cpus(unsigned int max_cpus)
+{
+ unsigned long base;
+ void __iomem *scu_base;
+
+ if (scu_a9_has_base()) {
+ base = scu_a9_get_base();
+ scu_base = ioremap(base, SZ_4K);
+ if (!scu_base) {
+ pr_err("ioremap(scu_base) failed\n");
+ return;
+ }
+ scu_enable(scu_base);
+ iounmap(scu_base);
+ }
+}
+
+static int hs_boot_secondary(unsigned int cpu, struct task_struct *idle)
+{
+ hs_set_cpu(cpu, true);
+ hs_set_cpu_jump(cpu, secondary_startup);
+ arch_send_wakeup_ipi_mask(cpumask_of(cpu));
+ return 0;
+}
+
+struct smp_operations hs_smp_ops __initdata = {
+ .smp_prepare_cpus = hs_smp_prepare_cpus,
+ .smp_boot_secondary = hs_boot_secondary,
+#ifdef CONFIG_HOTPLUG_CPU
+ .cpu_die = hs_cpu_die,
+ .cpu_kill = hs_cpu_kill,
+#endif
+};
diff --git a/arch/arm/mach-hs/pm.c b/arch/arm/mach-hs/pm.c
new file mode 100644
index 000000000000..efbca0e555b8
--- /dev/null
+++ b/arch/arm/mach-hs/pm.c
@@ -0,0 +1,495 @@
+/*
+ * Power Management suspend/resume routines for HiSilicon platform
+ *
+ * Copyright © 2011-2013 HiSilicon Technologies Co., Ltd.
+ * http://www.hisilicon.com
+ * Copyright © 2012-2013 Linaro Ltd.
+ * http://www.linaro.org
+ *
+ * Author: Guodong Xu <guodong.xu@linaro.org>
+ *
+ * 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.
+ *
+ */
+
+#define CONFIG_HSK3_RTC_WAKEUP
+#define CONFIG_HSK3_CONSOLE_WORKAROUND
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pm.h>
+#include <linux/suspend.h>
+#include <linux/cpu.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <asm/memory.h>
+#include <linux/delay.h>
+#include <linux/suspend.h>
+#include <asm/mach/time.h>
+#include <linux/slab.h>
+#include <asm/io.h>
+#include <linux/clk.h>
+#include <asm/cacheflush.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+#include <linux/of_gpio.h>
+#include <linux/cpu_pm.h>
+#include <asm/fncpy.h>
+#include "core.h"
+#include "hipm.h"
+#ifdef CONFIG_HSK3_RTC_WAKEUP
+#include <linux/irqchip/arm-gic.h>
+#include <linux/irq.h>
+#endif
+#ifdef CONFIG_HSK3_CONSOLE_WORKAROUND
+#include <linux/console.h>
+#endif
+
+/* resources in power management */
+struct iomap_resource {
+ struct resource *res;
+ void __iomem *virt_addr;
+};
+
+struct pm_resources {
+ struct iomap_resource pmu_spi;
+ struct iomap_resource secram;
+ struct iomap_resource pctrl;
+ struct iomap_resource a9_per;
+#ifdef CONFIG_HSK3_CONSOLE_WORKAROUND
+ struct iomap_resource uart0;
+ struct iomap_resource io;
+#endif
+};
+
+struct pm_resources hs_pm_resources;
+void __iomem *timer0_base_addr;
+void __iomem *hs_secram_va_base;
+void __iomem *hs_a9per_va_base;
+void __iomem *hs_pctrl_va_base;
+void __iomem *hs_pmuspi_va_base;
+
+#ifdef CONFIG_HSK3_CONSOLE_WORKAROUND
+static void __iomem *hs_uart0_va_base;
+static void __iomem *hs_io_va_base;
+
+/* re-init debug uart */
+static void debuguart_reinit(void)
+{
+ void __iomem *usctrl_base = hs_sctrl_base;
+ void __iomem *uuart_base = hs_uart0_va_base;
+ void __iomem *io_base = hs_io_va_base;
+ unsigned int uregv = 0;
+
+ /* Config necessary IOMG configuration */
+ writel(0, (io_base + 0xF4));
+
+ /* config necessary IOCG configuration */
+ writel(0, (io_base + 0xA08));
+ writel(0, (io_base + 0xA0C));
+
+ /* disable clk */
+ uregv = 0x10000;
+ writel(uregv, (usctrl_base + 0x44));
+
+ /* select 26MHz clock */
+ uregv = (1 << 23);
+ writel(uregv, (usctrl_base + 0x100));
+
+ /* enable clk */
+ uregv = 0x10000;
+ writel(uregv, (usctrl_base + 0x40));
+
+ /* disable recieve and send */
+ uregv = 0x0;
+ writel(uregv, (uuart_base + 0x30));
+
+ /* enable FIFO */
+ uregv = 0x70;
+ writel(uregv, (uuart_base + 0x2c));
+
+ /* set baudrate */
+ uregv = 0xE;
+ writel(uregv, (uuart_base + 0x24));
+
+ uregv = 0x7;
+ writel(uregv, (uuart_base + 0x28));
+
+ /* clear buffer */
+ uregv = readl(uuart_base);
+
+ /* enable FIFO */
+ uregv = 0x70;
+ writel(uregv, (uuart_base + 0x2C));
+
+ /* set FIFO depth */
+ uregv = 0x10A;
+ writel(uregv, (uuart_base + 0x34));
+
+ uregv = 0x50;
+ writel(uregv, (uuart_base + 0x38));
+
+ /* enable uart trans */
+ uregv = 0xF01;
+ writel(uregv, (uuart_base + 0x30));
+}
+#endif /* CONFIG_HSK3_CONSOLE_WORKAROUND */
+
+/* power-off GPIO pin handle */
+static int pmu_power_off_handle;
+
+/* system power off func */
+static void hisik3_power_off(void)
+{
+ int ret;
+
+ ret = gpio_request(pmu_power_off_handle, 0);
+ if (ret != 0)
+ pr_emerg("request PMU_POWER_OFF gpio error:%d\n", ret);
+
+ /* clear HRST_REG */
+ writel(0, PMU_HRST_REG);
+
+ while (1) {
+ pr_emerg("system power off now\n");
+
+ gpio_direction_output(pmu_power_off_handle, 0);
+ gpio_set_value(pmu_power_off_handle, 0);
+
+ msleep(1000);
+ }
+
+ gpio_free(pmu_power_off_handle);
+}
+
+static int wrapper_hs_godpsleep(void)
+{
+
+ hilpm_cpu_godpsleep();
+
+#ifdef CONFIG_HSK3_CONSOLE_WORKAROUND
+ /* debuguart needs to be reinit when "no_console_suspend" is set.
+ */
+ if (!console_suspend_enabled)
+ debuguart_reinit();
+#endif
+
+ return 0;
+}
+
+static int hisik3_pm_enter(suspend_state_t state)
+{
+ void __iomem *addr;
+ unsigned long flage = 0;
+
+ pr_notice("[PM] Enter sleep, in %s()\n", __func__);
+
+ switch (state) {
+ case PM_SUSPEND_STANDBY:
+ case PM_SUSPEND_MEM:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* store master cpu resume addree into SCTRL */
+ addr = (MASTER_SR_BACK_PHY_ADDR - REG_BASE_SCTRL) + hs_sctrl_base;
+ writel(hisi_v2p(master_cpu_resume), addr);
+
+ /* copy securam code */
+ fncpy(hs_secram_va_base + DPSLEEP_CODE_ADDR_OFFSET,
+ &hs_finish_suspend, DPSLEEP_CODE_LEN);
+
+ local_irq_save(flage);
+
+#ifdef CONFIG_CACHE_L2X0
+ outer_flush_all();
+ outer_disable();
+#endif
+ /* config pmu low power */
+ pmulowpower(1);
+
+ /* Entering deep sleep */
+ wrapper_hs_godpsleep();
+
+ /*PMU regs restore*/
+ pmulowpower(0);
+
+#ifdef CONFIG_CACHE_L2X0
+ outer_resume();
+#endif
+
+ flush_cache_all();
+
+ local_irq_restore(flage);
+
+ pr_notice("[PM] Restore OK\n");
+
+ return 0;
+}
+
+static const struct platform_suspend_ops hisik3_pm_ops = {
+ .enter = hisik3_pm_enter,
+ .valid = suspend_valid_only_mem,
+};
+
+static int hs_pm_get_resources(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct resource *res;
+ int ret = 0;
+
+ /* get the base address of pmu_spi */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ ret = -ENOMEM;
+ dev_err(dev, "platform_get_resource 0 err, ret=%d\n", ret);
+ goto error_res_1;
+ }
+ hs_pm_resources.pmu_spi.res = res;
+ hs_pm_resources.pmu_spi.virt_addr = ioremap(res->start,
+ resource_size(res));
+ if (!hs_pm_resources.pmu_spi.virt_addr) {
+ ret = -ENOMEM;
+ dev_err(dev, "cannot ioremap pmu_spi register memory\n");
+ goto error_res_1;
+ }
+ hs_pmuspi_va_base = hs_pm_resources.pmu_spi.virt_addr;
+
+ /* get the base address of secram */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!res) {
+ ret = -ENOMEM;
+ dev_err(dev, "platform_get_resource 1 err, ret=%d\n", ret);
+ goto error_res_2;
+ }
+ hs_pm_resources.secram.res = res;
+ hs_pm_resources.secram.virt_addr = ioremap(res->start,
+ resource_size(res));
+ if (!hs_pm_resources.secram.virt_addr) {
+ ret = -ENOMEM;
+ dev_err(dev, "cannot ioremap secram register memory\n");
+ goto error_res_2;
+ }
+ hs_secram_va_base = hs_pm_resources.secram.virt_addr;
+
+ /* get the base address of pctrl */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+ if (!res) {
+ ret = -ENOMEM;
+ dev_err(dev, "platform_get_resource 2 err, ret=%d\n", ret);
+ goto error_res_3;
+ }
+ hs_pm_resources.pctrl.res = res;
+ hs_pm_resources.pctrl.virt_addr = ioremap(res->start,
+ resource_size(res));
+ if (!hs_pm_resources.pctrl.virt_addr) {
+ ret = -ENOMEM;
+ dev_err(dev, "cannot ioremap pctrl register memory\n");
+ goto error_res_3;
+ }
+ hs_pctrl_va_base = hs_pm_resources.pctrl.virt_addr;
+
+ /* get the base address of a9_per */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
+ if (!res) {
+ ret = -ENOMEM;
+ dev_err(dev, "platform_get_resource 3 err, ret=%d\n", ret);
+ goto error_res_4;
+ }
+ hs_pm_resources.a9_per.res = res;
+ hs_pm_resources.a9_per.virt_addr = ioremap(res->start,
+ resource_size(res));
+ if (!hs_pm_resources.a9_per.virt_addr) {
+ ret = -ENOMEM;
+ dev_err(dev, "cannot ioremap a9_per register memory\n");
+ goto error_res_4;
+ }
+ hs_a9per_va_base = hs_pm_resources.a9_per.virt_addr;
+
+#ifdef CONFIG_HSK3_CONSOLE_WORKAROUND
+ /* get the base address of uart0 */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 4);
+ if (!res) {
+ ret = -ENOMEM;
+ dev_err(dev, "platform_get_resource 4 err, ret=%d\n", ret);
+ goto error_res_5;
+ }
+ hs_pm_resources.uart0.res = res;
+ hs_pm_resources.uart0.virt_addr = ioremap(res->start,
+ resource_size(res));
+ if (!hs_pm_resources.uart0.virt_addr) {
+ ret = -ENOMEM;
+ dev_err(dev, "cannot ioremap uart0 register memory\n");
+ goto error_res_5;
+ }
+ hs_uart0_va_base = hs_pm_resources.uart0.virt_addr;
+
+ /* get the base address of io */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 5);
+ if (!res) {
+ ret = -ENOMEM;
+ dev_err(dev, "platform_get_resource 5 err, ret=%d\n", ret);
+ goto error_res_6;
+ }
+ hs_pm_resources.io.res = res;
+ hs_pm_resources.io.virt_addr = ioremap(res->start,
+ resource_size(res));
+ if (!hs_pm_resources.io.virt_addr) {
+ ret = -ENOMEM;
+ dev_err(dev, "cannot ioremap io register memory\n");
+ goto error_res_6;
+ }
+ hs_io_va_base = hs_pm_resources.io.virt_addr;
+#endif /* CONFIG_HSK3_CONSOLE_WORKAROUND */
+
+ /* get pmu_power_off GPIO */
+ pmu_power_off_handle = of_get_named_gpio(np, "pmu-power-hold-gpios", 0);
+
+ if (!gpio_is_valid(pmu_power_off_handle)) {
+ dev_err(dev, "Fail to get pmu_power_off gpio, err=%d\n",
+ pmu_power_off_handle);
+ ret = pmu_power_off_handle;
+ goto error_pmu_gpio;
+ }
+
+ goto get_res_end;
+
+error_pmu_gpio:
+#ifdef CONFIG_HSK3_CONSOLE_WORKAROUND
+ iounmap(hs_pm_resources.io.virt_addr);
+error_res_6:
+ iounmap(hs_pm_resources.uart0.virt_addr);
+error_res_5:
+#endif
+ iounmap(hs_pm_resources.a9_per.virt_addr);
+error_res_4:
+ iounmap(hs_pm_resources.pctrl.virt_addr);
+error_res_3:
+ iounmap(hs_pm_resources.secram.virt_addr);
+error_res_2:
+ iounmap(hs_pm_resources.pmu_spi.virt_addr);
+error_res_1:
+
+get_res_end:
+ return ret;
+}
+
+static int hs_pm_free_resources(struct platform_device *pdev)
+{
+#ifdef CONFIG_HSK3_CONSOLE_WORKAROUND
+ iounmap(hs_pm_resources.io.virt_addr);
+ iounmap(hs_pm_resources.uart0.virt_addr);
+#endif /* CONFIG_HSK3_CONSOLE_WORKAROUND */
+ iounmap(hs_pm_resources.a9_per.virt_addr);
+ iounmap(hs_pm_resources.pctrl.virt_addr);
+ iounmap(hs_pm_resources.secram.virt_addr);
+ iounmap(hs_pm_resources.pmu_spi.virt_addr);
+ return 0;
+}
+
+#ifdef CONFIG_HSK3_RTC_WAKEUP
+static int hs_set_wake(struct irq_data *data, unsigned int state)
+{
+ return 0;
+}
+#endif
+
+static int hs_pm_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ void __iomem *addr;
+ int ret = 0;
+
+ /* alloc memmory for suspend */
+ hi_cpu_godpsleep_ddrbase = (unsigned long)kzalloc(
+ (SR_PROTECT_CTX_BUFF_SIZE), GFP_DMA|GFP_KERNEL);
+ if (!hi_cpu_godpsleep_ddrbase) {
+ dev_err(dev, "kzalloc err for hi_cpu_godpsleep_ddrbase!\n");
+ return -ENOMEM;
+ }
+
+ hi_cpu_godpsleep_phybase = hisi_v2p(hi_cpu_godpsleep_ddrbase);
+
+ /* get resources, parse from device tree */
+ ret = hs_pm_get_resources(pdev);
+ if (ret) {
+ dev_err(dev, "hs_pm_get_resources err, ret=%d\n", ret);
+ goto error_res;
+ }
+
+#ifdef CONFIG_CPU_IDLE
+ /* hilpm_cpu_godpsleep() use disable_mmu() and enable_mmu()
+ * which running in securam.
+ * we copy the two functions during init phase
+ */
+ hilpm_cp_cpuidle_code();
+#endif
+
+ addr = hs_sctrl_base + 0x10;
+ writel(SCXTALCTRL_CFG_VAL_200MS, addr);
+
+ suspend_set_ops(&hisik3_pm_ops);
+
+ /* power off function */
+ pm_power_off = hisik3_power_off;
+
+#ifdef CONFIG_HSK3_RTC_WAKEUP
+ /* set wakeup funciton */
+ gic_arch_extn.irq_set_wake = hs_set_wake;
+#endif
+
+ goto probe_end;
+
+error_res:
+ kfree((void *)hi_cpu_godpsleep_ddrbase);
+probe_end:
+ return ret;
+}
+
+static int hs_pm_remove(struct platform_device *pdev)
+{
+ hs_pm_free_resources(pdev);
+ kfree((void *)hi_cpu_godpsleep_ddrbase);
+ return 0;
+}
+
+static struct of_device_id of_hs_pm_match_tbl[] = {
+ {
+ .compatible = "hisilicon,hs-power-management",
+ },
+ { /* end */ }
+};
+
+static struct platform_driver hs_pm_driver = {
+ .driver = {
+ .name = "hs_pm",
+ .owner = THIS_MODULE,
+ .of_match_table = of_hs_pm_match_tbl,
+ },
+ .probe = hs_pm_probe,
+ .remove = hs_pm_remove,
+};
+
+static int __init hs_pm_init(void)
+{
+ return platform_driver_register(&hs_pm_driver);
+}
+module_init(hs_pm_init);
+
+static void __exit hs_pm_exit(void)
+{
+ platform_driver_unregister(&hs_pm_driver);
+}
+module_exit(hs_pm_exit);
+
+MODULE_AUTHOR("Guodong Xu <guodong.xu@linaro.org>");
+MODULE_DESCRIPTION("HiSilicon power management driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-hs/system.c b/arch/arm/mach-hs/system.c
new file mode 100644
index 000000000000..32cb26039a24
--- /dev/null
+++ b/arch/arm/mach-hs/system.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2013 Linaro Ltd.
+ * Copyright (c) 2013 Hisilicon Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+#include <linux/io.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+
+#include <asm/proc-fns.h>
+#include <asm/smp_plat.h>
+
+#include "core.h"
+
+void __iomem *hs_sctrl_base;
+static int hs_smp_reg;
+static int hs_resume_reg;
+static int hs_reboot_reg;
+
+void hs_map_io(void)
+{
+ struct device_node *np;
+
+ np = of_find_compatible_node(NULL, NULL, "hisilicon,sctrl");
+ if (np) {
+ hs_sctrl_base = of_iomap(np, 0);
+ if (!hs_sctrl_base)
+ pr_err("of_iomap(sctrl_base) failed\n");
+ of_property_read_u32(np, "smp_reg", &hs_smp_reg);
+ of_property_read_u32(np, "resume_reg", &hs_resume_reg);
+ of_property_read_u32(np, "reboot_reg", &hs_reboot_reg);
+ }
+}
+
+void hs_set_cpu_jump(int cpu, void *jump_addr)
+{
+ int offset = hs_smp_reg;
+
+ cpu = cpu_logical_map(cpu);
+ if (cpu > 0)
+ offset += 0x04 * (cpu - 1);
+ writel_relaxed(virt_to_phys(jump_addr), hs_sctrl_base + offset);
+}
+
+int hs_get_cpu_jump(int cpu)
+{
+ int offset = hs_smp_reg;
+
+ cpu = cpu_logical_map(cpu);
+ if (cpu > 0)
+ offset += 0x04 * (cpu - 1);
+ return readl_relaxed(hs_sctrl_base + offset);
+}
+
+void hs_restart(char mode, const char *cmd)
+{
+ writel_relaxed(0xdeadbeef, hs_sctrl_base + hs_reboot_reg);
+
+ while (1)
+ cpu_do_idle();
+}
+
diff --git a/arch/arm/mach-imx/clk.h b/arch/arm/mach-imx/clk.h
index d9d9d9c66dff..cdc67918cd37 100644
--- a/arch/arm/mach-imx/clk.h
+++ b/arch/arm/mach-imx/clk.h
@@ -77,7 +77,8 @@ static inline struct clk *imx_clk_gate(const char *name, const char *parent,
static inline struct clk *imx_clk_mux(const char *name, void __iomem *reg,
u8 shift, u8 width, const char **parents, int num_parents)
{
- return clk_register_mux(NULL, name, parents, num_parents, 0, reg, shift,
+ return clk_register_mux(NULL, name, parents, num_parents,
+ CLK_SET_RATE_NO_REPARENT, reg, shift,
width, 0, &imx_ccm_lock);
}
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index d0d9b2124752..4efa404078e6 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -83,4 +83,5 @@ config COMMON_CLK_AXI_CLKGEN
endmenu
+source "drivers/clk/hisilicon/Kconfig"
source "drivers/clk/mvebu/Kconfig"
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 137d3e730f86..9fa7b73533d5 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_COMMON_CLK) += clk-composite.o
obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o
obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o
obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o
+obj-$(CONFIG_ARCH_HS) += hisilicon/
obj-$(CONFIG_ARCH_MXS) += mxs/
obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/
obj-$(CONFIG_PLAT_SPEAR) += spear/
diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c
index 15114febfd92..790306e921c8 100644
--- a/drivers/clk/clk-gate.c
+++ b/drivers/clk/clk-gate.c
@@ -53,12 +53,18 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
if (gate->lock)
spin_lock_irqsave(gate->lock, flags);
- reg = readl(gate->reg);
-
- if (set)
- reg |= BIT(gate->bit_idx);
- else
- reg &= ~BIT(gate->bit_idx);
+ if (gate->flags & CLK_GATE_HIWORD_MASK) {
+ reg = BIT(gate->bit_idx + 16);
+ if (set)
+ reg |= BIT(gate->bit_idx);
+ } else {
+ reg = readl(gate->reg);
+
+ if (set)
+ reg |= BIT(gate->bit_idx);
+ else
+ reg &= ~BIT(gate->bit_idx);
+ }
writel(reg, gate->reg);
@@ -121,6 +127,13 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
struct clk *clk;
struct clk_init_data init;
+ if (clk_gate_flags & CLK_GATE_HIWORD_MASK) {
+ if (bit_idx > 16) {
+ pr_err("gate bit exceeds LOWORD field\n");
+ return ERR_PTR(-EINVAL);
+ }
+ }
+
/* allocate the gate */
gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL);
if (!gate) {
diff --git a/drivers/clk/clk-hi3xxx.c b/drivers/clk/clk-hi3xxx.c
new file mode 100644
index 000000000000..ac1520b49729
--- /dev/null
+++ b/drivers/clk/clk-hi3xxx.c
@@ -0,0 +1,643 @@
+/*
+ * Hisilicon clock driver
+ *
+ * Copyright (c) 2012-2013 Hisilicon Limited.
+ * Copyright (c) 2012-2013 Linaro Limited.
+ *
+ * Author: Haojian Zhuang <haojian.zhuang@linaro.org>
+ * Xin Li <li.xin@linaro.org>
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/clk-provider.h>
+#include <linux/clk-private.h>
+#include <linux/clkdev.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+
+#define HI3620_DISABLE_OFF 0x4
+#define HI3620_STATUS_OFF 0x8
+
+#define WIDTH_TO_MASK(width) ((1 << (width)) - 1)
+
+/*
+ * The reverse of DIV_ROUND_UP: The maximum number which
+ * divided by m is r
+ */
+#define MULT_ROUND_UP(r, m) ((r) * (m) + (m) - 1)
+
+struct hi3620_periclk {
+ struct clk_hw hw;
+ void __iomem *enable; /* enable register */
+ void __iomem *reset; /* reset register */
+ u32 ebits; /* bits in enable/disable register */
+ u32 rbits; /* bits in reset/unreset register */
+ spinlock_t *lock;
+};
+
+struct hi3620_muxclk {
+ struct clk_hw hw;
+ void __iomem *reg; /* mux register */
+ u8 shift;
+ u8 width;
+ u32 mbits; /* mask bits in mux register */
+ spinlock_t *lock;
+};
+
+struct hi3620_divclk {
+ struct clk_hw hw;
+ void __iomem *reg; /* divider register */
+ u8 shift;
+ u8 width;
+ u32 mbits; /* mask bits in divider register */
+ const struct clk_div_table *table;
+ spinlock_t *lock;
+};
+
+struct hs_clk {
+ void __iomem *pmctrl;
+ void __iomem *sctrl;
+ spinlock_t lock;
+};
+
+static void __init hs_init_clocks(void);
+
+static struct hs_clk hs_clk;
+
+static int hi3620_clkgate_prepare(struct clk_hw *hw)
+{
+ struct hi3620_periclk *pclk;
+ unsigned long flags = 0;
+
+ pclk = container_of(hw, struct hi3620_periclk, hw);
+
+ if (pclk->lock)
+ spin_lock_irqsave(pclk->lock, flags);
+ writel_relaxed(pclk->ebits, pclk->enable + HI3620_DISABLE_OFF);
+ writel_relaxed(pclk->rbits, pclk->reset + HI3620_DISABLE_OFF);
+ readl_relaxed(pclk->reset + HI3620_STATUS_OFF);
+ if (pclk->lock)
+ spin_unlock_irqrestore(pclk->lock, flags);
+ return 0;
+}
+
+static int hi3620_clkgate_enable(struct clk_hw *hw)
+{
+ struct hi3620_periclk *pclk;
+ unsigned long flags = 0;
+
+ pclk = container_of(hw, struct hi3620_periclk, hw);
+ if (pclk->lock)
+ spin_lock_irqsave(pclk->lock, flags);
+ writel_relaxed(pclk->ebits, pclk->enable);
+ readl_relaxed(pclk->enable + HI3620_STATUS_OFF);
+ if (pclk->lock)
+ spin_unlock_irqrestore(pclk->lock, flags);
+ return 0;
+}
+
+static void hi3620_clkgate_disable(struct clk_hw *hw)
+{
+ struct hi3620_periclk *pclk;
+ unsigned long flags = 0;
+
+ pclk = container_of(hw, struct hi3620_periclk, hw);
+ if (pclk->lock)
+ spin_lock_irqsave(pclk->lock, flags);
+ writel_relaxed(pclk->ebits, pclk->enable + HI3620_DISABLE_OFF);
+ readl_relaxed(pclk->enable + HI3620_STATUS_OFF);
+ if (pclk->lock)
+ spin_unlock_irqrestore(pclk->lock, flags);
+}
+
+static struct clk_ops hi3620_clkgate_ops = {
+ .prepare = hi3620_clkgate_prepare,
+ .enable = hi3620_clkgate_enable,
+ .disable = hi3620_clkgate_disable,
+};
+
+static void __init hi3620_clkgate_setup(struct device_node *np)
+{
+ struct hi3620_periclk *pclk;
+ struct clk_init_data *init;
+ struct clk *clk;
+ const char *clk_name, *name, **parent_names;
+ u32 rdata[2], gdata[2];
+
+ if (!hs_clk.sctrl)
+ return;
+
+ if (of_property_read_string(np, "clock-output-names", &clk_name))
+ return;
+ if (of_property_read_u32_array(np, "hisilicon,hi3620-clkreset",
+ &rdata[0], 2))
+ return;
+ if (of_property_read_u32_array(np, "hisilicon,hi3620-clkgate",
+ &gdata[0], 2))
+ return;
+
+ /* gate only has the fixed parent */
+ parent_names = kzalloc(sizeof(char *), GFP_KERNEL);
+ if (!parent_names)
+ return;
+ parent_names[0] = of_clk_get_parent_name(np, 0);
+
+ pclk = kzalloc(sizeof(*pclk), GFP_KERNEL);
+ if (!pclk)
+ goto err_pclk;
+
+ init = kzalloc(sizeof(*init), GFP_KERNEL);
+ if (!init)
+ goto err_init;
+ init->name = kstrdup(clk_name, GFP_KERNEL);
+ init->ops = &hi3620_clkgate_ops;
+ init->flags = CLK_SET_RATE_PARENT;
+ init->parent_names = parent_names;
+ init->num_parents = 1;
+
+ pclk->reset = hs_clk.sctrl + rdata[0];
+ pclk->rbits = rdata[1];
+ pclk->enable = hs_clk.sctrl + gdata[0];
+ pclk->ebits = gdata[1];
+ pclk->lock = &hs_clk.lock;
+ pclk->hw.init = init;
+
+ clk = clk_register(NULL, &pclk->hw);
+ if (IS_ERR(clk))
+ goto err_clk;
+ if (!of_property_read_string(np, "clock-names", &name))
+ clk_register_clkdev(clk, name, NULL);
+ of_clk_add_provider(np, of_clk_src_simple_get, clk);
+ return;
+err_clk:
+ kfree(init);
+err_init:
+ kfree(pclk);
+err_pclk:
+ kfree(parent_names);
+}
+
+static u8 hi3620_clk_get_parent(struct clk_hw *hw)
+{
+ struct hi3620_muxclk *mclk;
+ u32 data;
+ unsigned long flags = 0;
+
+ mclk = container_of(hw, struct hi3620_muxclk, hw);
+
+ if (mclk->lock)
+ spin_lock_irqsave(mclk->lock, flags);
+
+ data = readl_relaxed(mclk->reg) >> mclk->shift;
+ data &= WIDTH_TO_MASK(mclk->width);
+
+ if (mclk->lock)
+ spin_unlock_irqrestore(mclk->lock, flags);
+
+ if (data >= __clk_get_num_parents(hw->clk))
+ return -EINVAL;
+
+ return (u8)data;
+}
+
+static int hi3620_clk_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct hi3620_muxclk *mclk;
+ u32 data;
+ unsigned long flags = 0;
+
+ mclk = container_of(hw, struct hi3620_muxclk, hw);
+
+ if (mclk->lock)
+ spin_lock_irqsave(mclk->lock, flags);
+
+ data = readl_relaxed(mclk->reg);
+ data &= ~(WIDTH_TO_MASK(mclk->width) << mclk->shift);
+ data |= index << mclk->shift;
+ writel_relaxed(data, mclk->reg);
+ /* set mask enable bits */
+ data |= mclk->mbits;
+ writel_relaxed(data, mclk->reg);
+
+ if (mclk->lock)
+ spin_unlock_irqrestore(mclk->lock, flags);
+
+ return 0;
+}
+
+static struct clk_ops hi3620_clkmux_ops = {
+ .get_parent = hi3620_clk_get_parent,
+ .set_parent = hi3620_clk_set_parent,
+};
+
+static void __init hi3620_clkmux_setup(struct device_node *np)
+{
+ struct hi3620_muxclk *mclk;
+ struct clk_init_data *init;
+ struct clk *clk;
+ const char *clk_name, **parent_names;
+ u32 rdata[2];
+ u8 num_parents;
+ int i;
+
+ hs_init_clocks();
+ if (!hs_clk.sctrl)
+ return;
+
+ if (of_property_read_string(np, "clock-output-names", &clk_name))
+ return;
+ if (of_property_read_u32_array(np, "hisilicon,hi3620-clkmux",
+ &rdata[0], 2))
+ return;
+ /* get the count of items in mux */
+ for (i = 0; ; i++) {
+ /* parent's #clock-cells property is always 0 */
+ if (!of_parse_phandle(np, "clocks", i))
+ break;
+ }
+ parent_names = kzalloc(sizeof(char *) * i, GFP_KERNEL);
+ if (!parent_names)
+ return;
+
+ for (num_parents = i, i = 0; i < num_parents; i++)
+ parent_names[i] = of_clk_get_parent_name(np, i);
+
+ mclk = kzalloc(sizeof(*mclk), GFP_KERNEL);
+ if (!mclk)
+ goto err_mclk;
+ init = kzalloc(sizeof(*init), GFP_KERNEL);
+ if (!init)
+ goto err_init;
+ init->name = kstrdup(clk_name, GFP_KERNEL);
+ init->ops = &hi3620_clkmux_ops;
+ init->flags = CLK_SET_RATE_PARENT;
+ init->parent_names = parent_names;
+ init->num_parents = num_parents;
+
+ mclk->reg = hs_clk.sctrl + rdata[0];
+ /* enable_mask bits are in higher 16bits */
+ mclk->mbits = rdata[1] << 16;
+ mclk->shift = ffs(rdata[1]) - 1;
+ mclk->width = fls(rdata[1]) - ffs(rdata[1]) + 1;
+ mclk->lock = &hs_clk.lock;
+ mclk->hw.init = init;
+
+ clk = clk_register(NULL, &mclk->hw);
+ if (IS_ERR(clk))
+ goto err_clk;
+ of_clk_add_provider(np, of_clk_src_simple_get, clk);
+
+ return;
+err_clk:
+ kfree(init);
+err_init:
+ kfree(mclk);
+err_mclk:
+ kfree(parent_names);
+}
+
+static void __init hs_clkgate_setup(struct device_node *np)
+{
+ struct clk *clk;
+ const char *clk_name, **parent_names, *name;
+ unsigned long flags = 0;
+ u32 data[2];
+
+ hs_init_clocks();
+ if (!hs_clk.sctrl)
+ return;
+ if (of_property_read_string(np, "clock-output-names", &clk_name))
+ return;
+ if (of_property_read_u32_array(np, "hisilicon,clkgate",
+ &data[0], 2))
+ return;
+ if (of_property_read_bool(np, "hisilicon,clkgate-inverted"))
+ flags = CLK_GATE_SET_TO_DISABLE;
+ /* gate only has the fixed parent */
+ parent_names = kzalloc(sizeof(char *), GFP_KERNEL);
+ if (!parent_names)
+ return;
+ parent_names[0] = of_clk_get_parent_name(np, 0);
+
+ clk = clk_register_gate(NULL, clk_name, parent_names[0], 0,
+ hs_clk.sctrl + data[0], (u8)data[1], flags,
+ &hs_clk.lock);
+ if (IS_ERR(clk))
+ goto err;
+ if (!of_property_read_string(np, "clock-names", &name))
+ clk_register_clkdev(clk, name, NULL);
+ of_clk_add_provider(np, of_clk_src_simple_get, clk);
+ return;
+err:
+ kfree(parent_names);
+}
+
+void __init hs_fixed_factor_setup(struct device_node *np)
+{
+ struct clk *clk;
+ const char *clk_name, **parent_names;
+ u32 data[2];
+
+ if (of_property_read_string(np, "clock-output-names", &clk_name))
+ return;
+ if (of_property_read_u32_array(np, "hisilicon,fixed-factor",
+ data, 2))
+ return ;
+ /* gate only has the fixed parent */
+ parent_names = kzalloc(sizeof(char *), GFP_KERNEL);
+ if (!parent_names)
+ return;
+ parent_names[0] = of_clk_get_parent_name(np, 0);
+
+ clk = clk_register_fixed_factor(NULL, clk_name, parent_names[0], 0,
+ data[0], data[1]);
+ if (IS_ERR(clk))
+ goto err;
+ of_clk_add_provider(np, of_clk_src_simple_get, clk);
+ return;
+err:
+ kfree(parent_names);
+}
+
+static unsigned int hi3620_get_table_maxdiv(const struct clk_div_table *table)
+{
+ unsigned int maxdiv = 0;
+ const struct clk_div_table *clkt;
+
+ for (clkt = table; clkt->div; clkt++)
+ if (clkt->div > maxdiv)
+ maxdiv = clkt->div;
+ return maxdiv;
+}
+
+static unsigned int hi3620_get_table_div(const struct clk_div_table *table,
+ unsigned int val)
+{
+ const struct clk_div_table *clkt;
+
+ for (clkt = table; clkt->div; clkt++)
+ if (clkt->val == val)
+ return clkt->div;
+ return 0;
+}
+
+static unsigned int hi3620_get_table_val(const struct clk_div_table *table,
+ unsigned int div)
+{
+ const struct clk_div_table *clkt;
+
+ for (clkt = table; clkt->div; clkt++)
+ if (clkt->div == div)
+ return clkt->val;
+ return 0;
+}
+
+static unsigned long hi3620_clkdiv_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct hi3620_divclk *dclk = container_of(hw, struct hi3620_divclk, hw);
+ unsigned int div, val;
+
+ val = readl_relaxed(dclk->reg) >> dclk->shift;
+ val &= WIDTH_TO_MASK(dclk->width);
+
+ div = hi3620_get_table_div(dclk->table, val);
+ if (!div) {
+ pr_warning("%s: Invalid divisor for clock %s\n", __func__,
+ __clk_get_name(hw->clk));
+ return parent_rate;
+ }
+
+ return parent_rate / div;
+}
+
+static bool hi3620_is_valid_table_div(const struct clk_div_table *table,
+ unsigned int div)
+{
+ const struct clk_div_table *clkt;
+
+ for (clkt = table; clkt->div; clkt++)
+ if (clkt->div == div)
+ return true;
+ return false;
+}
+
+static int hi3620_clkdiv_bestdiv(struct clk_hw *hw, unsigned long rate,
+ unsigned long *best_parent_rate)
+{
+ struct hi3620_divclk *dclk = container_of(hw, struct hi3620_divclk, hw);
+ struct clk *clk_parent = __clk_get_parent(hw->clk);
+ int i, bestdiv = 0;
+ unsigned long parent_rate, best = 0, now, maxdiv;
+
+ maxdiv = hi3620_get_table_maxdiv(dclk->table);
+
+ if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) {
+ parent_rate = *best_parent_rate;
+ bestdiv = DIV_ROUND_UP(parent_rate, rate);
+ bestdiv = bestdiv == 0 ? 1 : bestdiv;
+ bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv;
+ return bestdiv;
+ }
+
+ /*
+ * The maximum divider we can use without overflowing
+ * unsigned long in rate * i below
+ */
+ maxdiv = min(ULONG_MAX / rate, maxdiv);
+
+ for (i = 1; i <= maxdiv; i++) {
+ if (!hi3620_is_valid_table_div(dclk->table, i))
+ continue;
+ parent_rate = __clk_round_rate(clk_parent,
+ MULT_ROUND_UP(rate, i));
+ now = parent_rate / i;
+ if (now <= rate && now > best) {
+ bestdiv = i;
+ best = now;
+ *best_parent_rate = parent_rate;
+ }
+ }
+
+ if (!bestdiv) {
+ bestdiv = hi3620_get_table_maxdiv(dclk->table);
+ *best_parent_rate = __clk_round_rate(clk_parent, 1);
+ }
+
+ return bestdiv;
+}
+
+static long hi3620_clkdiv_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ int div;
+
+ if (!rate)
+ rate = 1;
+ div = hi3620_clkdiv_bestdiv(hw, rate, prate);
+
+ return *prate / div;
+}
+
+static int hi3620_clkdiv_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct hi3620_divclk *dclk = container_of(hw, struct hi3620_divclk, hw);
+ unsigned int div, value;
+ unsigned long flags = 0;
+ u32 data;
+
+ div = parent_rate / rate;
+ value = hi3620_get_table_val(dclk->table, div);
+
+ if (value > WIDTH_TO_MASK(dclk->width))
+ value = WIDTH_TO_MASK(dclk->width);
+
+ if (dclk->lock)
+ spin_lock_irqsave(dclk->lock, flags);
+
+ data = readl_relaxed(dclk->reg);
+ data &= ~(WIDTH_TO_MASK(dclk->width) << dclk->shift);
+ data |= value << dclk->shift;
+ data |= dclk->mbits;
+ writel_relaxed(data, dclk->reg);
+
+ if (dclk->lock)
+ spin_unlock_irqrestore(dclk->lock, flags);
+
+ return 0;
+}
+
+static struct clk_ops hi3620_clkdiv_ops = {
+ .recalc_rate = hi3620_clkdiv_recalc_rate,
+ .round_rate = hi3620_clkdiv_round_rate,
+ .set_rate = hi3620_clkdiv_set_rate,
+};
+
+void __init hi3620_clkdiv_setup(struct device_node *np)
+{
+ struct clk *clk;
+ const char *clk_name, **parent_names;
+ struct clk_init_data *init;
+ struct clk_div_table *table;
+ struct hi3620_divclk *dclk;
+ unsigned int table_num;
+ int i;
+ u32 data[2];
+ const char *propname = "hisilicon,clkdiv-table";
+ const char *cellname = "#hisilicon,clkdiv-table-cells";
+ struct of_phandle_args div_table;
+
+ hs_init_clocks();
+ if (!hs_clk.sctrl)
+ return;
+
+ if (of_property_read_string(np, "clock-output-names", &clk_name))
+ return;
+ if (of_property_read_u32_array(np, "hisilicon,clkdiv",
+ &data[0], 2))
+ return;
+
+ /*process the div_table*/
+ for (i = 0; ; i++) {
+ if (of_parse_phandle_with_args(np, propname, cellname,
+ i, &div_table))
+ break;
+ }
+
+ /*table ends with <0, 0>, so plus one to table_num*/
+ table_num = i + 1;
+
+ table = kzalloc(sizeof(struct clk_div_table) * table_num, GFP_KERNEL);
+ if (!table)
+ return ;
+
+ for (i = 0; ; i++) {
+ if (of_parse_phandle_with_args(np, propname, cellname,
+ i, &div_table))
+ break;
+
+ table[i].val = div_table.args[0];
+ table[i].div = div_table.args[1];
+ }
+
+ /* gate only has the fixed parent */
+ parent_names = kzalloc(sizeof(char *), GFP_KERNEL);
+ if (!parent_names)
+ goto err_par;
+ parent_names[0] = of_clk_get_parent_name(np, 0);
+
+ dclk = kzalloc(sizeof(*dclk), GFP_KERNEL);
+ if (!dclk)
+ goto err_dclk;
+ init = kzalloc(sizeof(*init), GFP_KERNEL);
+ if (!init)
+ goto err_init;
+ init->name = kstrdup(clk_name, GFP_KERNEL);
+ init->ops = &hi3620_clkdiv_ops;
+ init->parent_names = parent_names;
+ init->num_parents = 1;
+
+ dclk->reg = hs_clk.sctrl + data[0];
+ dclk->shift = ffs(data[1]) - 1;
+ dclk->width = fls(data[1]) - ffs(data[1]) + 1;
+ dclk->mbits = data[1] << 16;
+ dclk->lock = &hs_clk.lock;
+ dclk->hw.init = init;
+ dclk->table = table;
+ clk = clk_register(NULL, &dclk->hw);
+ if (IS_ERR(clk))
+ goto err_clk;
+ of_clk_add_provider(np, of_clk_src_simple_get, clk);
+ return;
+err_clk:
+ kfree(init);
+err_init:
+ kfree(dclk);
+err_dclk:
+ kfree(parent_names);
+err_par:
+ kfree(table);
+}
+CLK_OF_DECLARE(hi3620_mux, "hisilicon,hi3620-clk-mux", hi3620_clkmux_setup)
+CLK_OF_DECLARE(hi3620_gate, "hisilicon,hi3620-clk-gate", hi3620_clkgate_setup)
+CLK_OF_DECLARE(hi3620_div, "hisilicon,hi3620-clk-div", hi3620_clkdiv_setup)
+CLK_OF_DECLARE(hs_gate, "hisilicon,clk-gate", hs_clkgate_setup)
+CLK_OF_DECLARE(hs_fixed, "hisilicon,clk-fixed-factor", hs_fixed_factor_setup)
+
+static void __init hs_init_clocks(void)
+{
+ struct device_node *node = NULL;
+
+ if (!hs_clk.pmctrl) {
+ /* map pmctrl registers */
+ node = of_find_compatible_node(NULL, NULL, "hisilicon,pmctrl");
+ hs_clk.pmctrl = of_iomap(node, 0);
+ WARN_ON(!hs_clk.pmctrl);
+ }
+
+ if (!hs_clk.sctrl) {
+ node = of_find_compatible_node(NULL, NULL, "hisilicon,sysctrl");
+ hs_clk.sctrl = of_iomap(node, 0);
+ }
+}
diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c
index 25b1734560d0..5af146ac500c 100644
--- a/drivers/clk/clk-mux.c
+++ b/drivers/clk/clk-mux.c
@@ -51,7 +51,7 @@ static u8 clk_mux_get_parent(struct clk_hw *hw)
for (i = 0; i < num_parents; i++)
if (mux->table[i] == val)
return i;
- return -EINVAL;
+ return 0;
}
if (val && (mux->flags & CLK_MUX_INDEX_BIT))
@@ -61,7 +61,7 @@ static u8 clk_mux_get_parent(struct clk_hw *hw)
val--;
if (val >= num_parents)
- return -EINVAL;
+ return 0;
return val;
}
@@ -70,6 +70,7 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
{
struct clk_mux *mux = to_clk_mux(hw);
u32 val;
+ u8 width = 0;
unsigned long flags = 0;
if (mux->table)
@@ -89,6 +90,13 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
val = readl(mux->reg);
val &= ~(mux->mask << mux->shift);
val |= index << mux->shift;
+ if (mux->flags & CLK_MUX_HIWORD_MASK) {
+ width = fls(mux->mask) - ffs(mux->mask) + 1;
+ if (width + mux->shift > 16)
+ pr_warn("mux value exceeds LOWORD field\n");
+ else
+ val |= mux->mask << (mux->shift + 16);
+ }
writel(val, mux->reg);
if (mux->lock)
@@ -100,6 +108,7 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
const struct clk_ops clk_mux_ops = {
.get_parent = clk_mux_get_parent,
.set_parent = clk_mux_set_parent,
+ .determine_rate = __clk_mux_determine_rate,
};
EXPORT_SYMBOL_GPL(clk_mux_ops);
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 1144e8c7579d..6b582f730a05 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -226,6 +226,35 @@ static const struct file_operations clk_dump_fops = {
.release = single_release,
};
+#ifdef DEBUG
+static int clk_rate_fops_get(void *data, u64 *rate)
+{
+ struct clk *clk = data;
+
+ *rate = clk->rate;
+
+ return 0;
+};
+
+static int clk_rate_fops_set(void *data, u64 rate)
+{
+ struct clk *clk = data;
+ int ret = 0;
+
+ ret = clk_prepare_enable(clk);
+ if (ret)
+ goto out;
+ clk_set_rate(clk, rate);
+ clk_disable_unprepare(clk);
+
+out:
+ return ret;
+};
+
+DEFINE_SIMPLE_ATTRIBUTE(clk_rate_fops, clk_rate_fops_get,
+ clk_rate_fops_set, "%llu\n");
+#endif
+
/* caller must hold prepare_lock */
static int clk_debug_create_one(struct clk *clk, struct dentry *pdentry)
{
@@ -243,8 +272,13 @@ static int clk_debug_create_one(struct clk *clk, struct dentry *pdentry)
clk->dentry = d;
+#ifdef DEBUG
+ d = debugfs_create_file("clk_rate", S_IWUSR | S_IRUGO, clk->dentry,
+ clk, &clk_rate_fops);
+#else
d = debugfs_create_u32("clk_rate", S_IRUGO, clk->dentry,
(u32 *)&clk->rate);
+#endif
if (!d)
goto err_out;
@@ -559,6 +593,19 @@ struct clk *__clk_get_parent(struct clk *clk)
return !clk ? NULL : clk->parent;
}
+struct clk *clk_get_parent_by_index(struct clk *clk, u8 index)
+{
+ if (!clk || index >= clk->num_parents)
+ return NULL;
+ else if (!clk->parents)
+ return __clk_lookup(clk->parent_names[index]);
+ else if (!clk->parents[index])
+ return clk->parents[index] =
+ __clk_lookup(clk->parent_names[index]);
+ else
+ return clk->parents[index];
+}
+
unsigned int __clk_get_enable_count(struct clk *clk)
{
return !clk ? 0 : clk->enable_count;
@@ -679,6 +726,55 @@ struct clk *__clk_lookup(const char *name)
return NULL;
}
+/*
+ * Helper for finding best parent to provide a given frequency. This can be used
+ * directly as a determine_rate callback (e.g. for a mux), or from a more
+ * complex clock that may combine a mux with other operations.
+ */
+long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *best_parent_rate,
+ struct clk **best_parent_p)
+{
+ struct clk *clk = hw->clk, *parent, *best_parent = NULL;
+ int i, num_parents;
+ unsigned long parent_rate, best = 0;
+
+ /* if NO_REPARENT flag set, pass through to current parent */
+ if (clk->flags & CLK_SET_RATE_NO_REPARENT) {
+ parent = clk->parent;
+ if (clk->flags & CLK_SET_RATE_PARENT)
+ best = __clk_round_rate(parent, rate);
+ else if (parent)
+ best = __clk_get_rate(parent);
+ else
+ best = __clk_get_rate(clk);
+ goto out;
+ }
+
+ /* find the parent that can provide the fastest rate <= rate */
+ num_parents = clk->num_parents;
+ for (i = 0; i < num_parents; i++) {
+ parent = clk_get_parent_by_index(clk, i);
+ if (!parent)
+ continue;
+ if (clk->flags & CLK_SET_RATE_PARENT)
+ parent_rate = __clk_round_rate(parent, rate);
+ else
+ parent_rate = __clk_get_rate(parent);
+ if (parent_rate <= rate && parent_rate > best) {
+ best_parent = parent;
+ best = parent_rate;
+ }
+ }
+
+out:
+ if (best_parent)
+ *best_parent_p = best_parent;
+ *best_parent_rate = best;
+
+ return best;
+}
+
/*** clk api ***/
void __clk_unprepare(struct clk *clk)
@@ -875,21 +971,24 @@ EXPORT_SYMBOL_GPL(clk_enable);
unsigned long __clk_round_rate(struct clk *clk, unsigned long rate)
{
unsigned long parent_rate = 0;
+ struct clk *parent;
if (!clk)
return 0;
- if (!clk->ops->round_rate) {
- if (clk->flags & CLK_SET_RATE_PARENT)
- return __clk_round_rate(clk->parent, rate);
- else
- return clk->rate;
- }
-
- if (clk->parent)
- parent_rate = clk->parent->rate;
-
- return clk->ops->round_rate(clk->hw, rate, &parent_rate);
+ parent = clk->parent;
+ if (parent)
+ parent_rate = parent->rate;
+
+ if (clk->ops->determine_rate)
+ return clk->ops->determine_rate(clk->hw, rate, &parent_rate,
+ &parent);
+ else if (clk->ops->round_rate)
+ return clk->ops->round_rate(clk->hw, rate, &parent_rate);
+ else if (clk->flags & CLK_SET_RATE_PARENT)
+ return __clk_round_rate(clk->parent, rate);
+ else
+ return clk->rate;
}
/**
@@ -1014,6 +1113,112 @@ unsigned long clk_get_rate(struct clk *clk)
}
EXPORT_SYMBOL_GPL(clk_get_rate);
+static u8 clk_fetch_parent_index(struct clk *clk, struct clk *parent)
+{
+ u8 i;
+
+ if (!clk->parents)
+ clk->parents = kzalloc((sizeof(struct clk*) * clk->num_parents),
+ GFP_KERNEL);
+
+ /*
+ * find index of new parent clock using cached parent ptrs,
+ * or if not yet cached, use string name comparison and cache
+ * them now to avoid future calls to __clk_lookup.
+ */
+ for (i = 0; i < clk->num_parents; i++) {
+ if (clk->parents && clk->parents[i] == parent)
+ break;
+ else if (!strcmp(clk->parent_names[i], parent->name)) {
+ if (clk->parents)
+ clk->parents[i] = __clk_lookup(parent->name);
+ break;
+ }
+ }
+
+ return i;
+}
+
+static void clk_reparent(struct clk *clk, struct clk *new_parent)
+{
+ /* avoid duplicate POST_RATE_CHANGE notifications */
+ if (new_parent->new_child == clk)
+ new_parent->new_child = NULL;
+
+ hlist_del(&clk->child_node);
+
+ if (new_parent)
+ hlist_add_head(&clk->child_node, &new_parent->children);
+ else
+ hlist_add_head(&clk->child_node, &clk_orphan_list);
+
+ clk->parent = new_parent;
+}
+
+static int __clk_set_parent(struct clk *clk, struct clk *parent, u8 p_index)
+{
+ unsigned long flags;
+ int ret = 0;
+ struct clk *old_parent = clk->parent;
+
+ /*
+ * Migrate prepare state between parents and prevent race with
+ * clk_enable().
+ *
+ * If the clock is not prepared, then a race with
+ * clk_enable/disable() is impossible since we already have the
+ * prepare lock (future calls to clk_enable() need to be preceded by
+ * a clk_prepare()).
+ *
+ * If the clock is prepared, migrate the prepared state to the new
+ * parent and also protect against a race with clk_enable() by
+ * forcing the clock and the new parent on. This ensures that all
+ * future calls to clk_enable() are practically NOPs with respect to
+ * hardware and software states.
+ */
+ if (clk->prepare_count) {
+ __clk_prepare(parent);
+ clk_enable(parent);
+ clk_enable(clk);
+ }
+
+ /* update the clk tree topology */
+ flags = clk_enable_lock();
+ clk_reparent(clk, parent);
+ clk_enable_unlock(flags);
+
+ /* change clock input source */
+ if (parent && clk->ops->set_parent)
+ ret = clk->ops->set_parent(clk->hw, p_index);
+
+ if (ret) {
+ flags = clk_enable_lock();
+ clk_reparent(clk, old_parent);
+ clk_enable_unlock(flags);
+
+ if (clk->prepare_count) {
+ clk_disable(clk);
+ clk_disable(parent);
+ __clk_unprepare(parent);
+ }
+ return ret;
+ }
+
+ /*
+ * Finish the migration of prepare state and undo the changes done
+ * for preventing a race with clk_enable().
+ */
+ if (clk->prepare_count) {
+ clk_disable(clk);
+ clk_disable(old_parent);
+ __clk_unprepare(old_parent);
+ }
+
+ /* update debugfs with new clk tree topology */
+ clk_debug_reparent(clk, parent);
+ return 0;
+}
+
/**
* __clk_speculate_rates
* @clk: first clk in the subtree
@@ -1058,18 +1263,25 @@ out:
return ret;
}
-static void clk_calc_subtree(struct clk *clk, unsigned long new_rate)
+static void clk_calc_subtree(struct clk *clk, unsigned long new_rate,
+ struct clk *new_parent, u8 p_index)
{
struct clk *child;
clk->new_rate = new_rate;
+ clk->new_parent = new_parent;
+ clk->new_parent_index = p_index;
+ /* include clk in new parent's PRE_RATE_CHANGE notifications */
+ clk->new_child = NULL;
+ if (new_parent && new_parent != clk->parent)
+ new_parent->new_child = clk;
hlist_for_each_entry(child, &clk->children, child_node) {
if (child->ops->recalc_rate)
child->new_rate = child->ops->recalc_rate(child->hw, new_rate);
else
child->new_rate = new_rate;
- clk_calc_subtree(child, child->new_rate);
+ clk_calc_subtree(child, child->new_rate, NULL, 0);
}
}
@@ -1080,50 +1292,63 @@ static void clk_calc_subtree(struct clk *clk, unsigned long new_rate)
static struct clk *clk_calc_new_rates(struct clk *clk, unsigned long rate)
{
struct clk *top = clk;
+ struct clk *old_parent, *parent;
unsigned long best_parent_rate = 0;
unsigned long new_rate;
+ u8 p_index = 0;
/* sanity */
if (IS_ERR_OR_NULL(clk))
return NULL;
/* save parent rate, if it exists */
- if (clk->parent)
- best_parent_rate = clk->parent->rate;
-
- /* never propagate up to the parent */
- if (!(clk->flags & CLK_SET_RATE_PARENT)) {
- if (!clk->ops->round_rate) {
- clk->new_rate = clk->rate;
- return NULL;
- }
- new_rate = clk->ops->round_rate(clk->hw, rate, &best_parent_rate);
+ parent = old_parent = clk->parent;
+ if (parent)
+ best_parent_rate = parent->rate;
+
+ /* find the closest rate and parent clk/rate */
+ if (clk->ops->determine_rate) {
+ new_rate = clk->ops->determine_rate(clk->hw, rate,
+ &best_parent_rate,
+ &parent);
+ } else if (clk->ops->round_rate) {
+ new_rate = clk->ops->round_rate(clk->hw, rate,
+ &best_parent_rate);
+ } else if (!parent || !(clk->flags & CLK_SET_RATE_PARENT)) {
+ /* pass-through clock without adjustable parent */
+ clk->new_rate = clk->rate;
+ return NULL;
+ } else {
+ /* pass-through clock with adjustable parent */
+ top = clk_calc_new_rates(parent, rate);
+ new_rate = parent->new_rate;
goto out;
}
- /* need clk->parent from here on out */
- if (!clk->parent) {
- pr_debug("%s: %s has NULL parent\n", __func__, clk->name);
+ /* some clocks must be gated to change parent */
+ if (parent != old_parent &&
+ (clk->flags & CLK_SET_PARENT_GATE) && clk->prepare_count) {
+ pr_debug("%s: %s not gated but wants to reparent\n",
+ __func__, clk->name);
return NULL;
}
- if (!clk->ops->round_rate) {
- top = clk_calc_new_rates(clk->parent, rate);
- new_rate = clk->parent->new_rate;
-
- goto out;
+ /* try finding the new parent index */
+ if (parent) {
+ p_index = clk_fetch_parent_index(clk, parent);
+ if (p_index == clk->num_parents) {
+ pr_debug("%s: clk %s can not be parent of clk %s\n",
+ __func__, parent->name, clk->name);
+ return NULL;
+ }
}
- new_rate = clk->ops->round_rate(clk->hw, rate, &best_parent_rate);
-
- if (best_parent_rate != clk->parent->rate) {
- top = clk_calc_new_rates(clk->parent, best_parent_rate);
-
- goto out;
- }
+ if ((clk->flags & CLK_SET_RATE_PARENT) && parent &&
+ best_parent_rate != parent->rate)
+ top = clk_calc_new_rates(parent, best_parent_rate);
out:
- clk_calc_subtree(clk, new_rate);
+ clk_calc_subtree(clk, new_rate, parent, p_index);
return top;
}
@@ -1135,7 +1360,7 @@ out:
*/
static struct clk *clk_propagate_rate_change(struct clk *clk, unsigned long event)
{
- struct clk *child, *fail_clk = NULL;
+ struct clk *child, *tmp_clk, *fail_clk = NULL;
int ret = NOTIFY_DONE;
if (clk->rate == clk->new_rate)
@@ -1148,9 +1373,19 @@ static struct clk *clk_propagate_rate_change(struct clk *clk, unsigned long even
}
hlist_for_each_entry(child, &clk->children, child_node) {
- clk = clk_propagate_rate_change(child, event);
- if (clk)
- fail_clk = clk;
+ /* Skip children who will be reparented to another clock */
+ if (child->new_parent && child->new_parent != clk)
+ continue;
+ tmp_clk = clk_propagate_rate_change(child, event);
+ if (tmp_clk)
+ fail_clk = tmp_clk;
+ }
+
+ /* handle the new child who might not be in clk->children yet */
+ if (clk->new_child) {
+ tmp_clk = clk_propagate_rate_change(clk->new_child, event);
+ if (tmp_clk)
+ fail_clk = tmp_clk;
}
return fail_clk;
@@ -1168,6 +1403,10 @@ static void clk_change_rate(struct clk *clk)
old_rate = clk->rate;
+ /* set parent */
+ if (clk->new_parent && clk->new_parent != clk->parent)
+ __clk_set_parent(clk, clk->new_parent, clk->new_parent_index);
+
if (clk->parent)
best_parent_rate = clk->parent->rate;
@@ -1182,8 +1421,16 @@ static void clk_change_rate(struct clk *clk)
if (clk->notifier_count && old_rate != clk->rate)
__clk_notify(clk, POST_RATE_CHANGE, old_rate, clk->rate);
- hlist_for_each_entry(child, &clk->children, child_node)
+ hlist_for_each_entry(child, &clk->children, child_node) {
+ /* Skip children who will be reparented to another clock */
+ if (child->new_parent && child->new_parent != clk)
+ continue;
clk_change_rate(child);
+ }
+
+ /* handle the new child who might not be in clk->children yet */
+ if (clk->new_child)
+ clk_change_rate(clk->new_child);
}
/**
@@ -1315,30 +1562,12 @@ static struct clk *__clk_init_parent(struct clk *clk)
kzalloc((sizeof(struct clk*) * clk->num_parents),
GFP_KERNEL);
- if (!clk->parents)
- ret = __clk_lookup(clk->parent_names[index]);
- else if (!clk->parents[index])
- ret = clk->parents[index] =
- __clk_lookup(clk->parent_names[index]);
- else
- ret = clk->parents[index];
+ ret = clk_get_parent_by_index(clk, index);
out:
return ret;
}
-static void clk_reparent(struct clk *clk, struct clk *new_parent)
-{
- hlist_del(&clk->child_node);
-
- if (new_parent)
- hlist_add_head(&clk->child_node, &new_parent->children);
- else
- hlist_add_head(&clk->child_node, &clk_orphan_list);
-
- clk->parent = new_parent;
-}
-
void __clk_reparent(struct clk *clk, struct clk *new_parent)
{
clk_reparent(clk, new_parent);
@@ -1346,104 +1575,6 @@ void __clk_reparent(struct clk *clk, struct clk *new_parent)
__clk_recalc_rates(clk, POST_RATE_CHANGE);
}
-static u8 clk_fetch_parent_index(struct clk *clk, struct clk *parent)
-{
- u8 i;
-
- if (!clk->parents)
- clk->parents = kzalloc((sizeof(struct clk*) * clk->num_parents),
- GFP_KERNEL);
-
- /*
- * find index of new parent clock using cached parent ptrs,
- * or if not yet cached, use string name comparison and cache
- * them now to avoid future calls to __clk_lookup.
- */
- for (i = 0; i < clk->num_parents; i++) {
- if (clk->parents && clk->parents[i] == parent)
- break;
- else if (!strcmp(clk->parent_names[i], parent->name)) {
- if (clk->parents)
- clk->parents[i] = __clk_lookup(parent->name);
- break;
- }
- }
-
- return i;
-}
-
-static int __clk_set_parent(struct clk *clk, struct clk *parent, u8 p_index)
-{
- unsigned long flags;
- int ret = 0;
- struct clk *old_parent = clk->parent;
- bool migrated_enable = false;
-
- /* migrate prepare */
- if (clk->prepare_count)
- __clk_prepare(parent);
-
- flags = clk_enable_lock();
-
- /* migrate enable */
- if (clk->enable_count) {
- __clk_enable(parent);
- migrated_enable = true;
- }
-
- /* update the clk tree topology */
- clk_reparent(clk, parent);
-
- clk_enable_unlock(flags);
-
- /* change clock input source */
- if (parent && clk->ops->set_parent)
- ret = clk->ops->set_parent(clk->hw, p_index);
-
- if (ret) {
- /*
- * The error handling is tricky due to that we need to release
- * the spinlock while issuing the .set_parent callback. This
- * means the new parent might have been enabled/disabled in
- * between, which must be considered when doing rollback.
- */
- flags = clk_enable_lock();
-
- clk_reparent(clk, old_parent);
-
- if (migrated_enable && clk->enable_count) {
- __clk_disable(parent);
- } else if (migrated_enable && (clk->enable_count == 0)) {
- __clk_disable(old_parent);
- } else if (!migrated_enable && clk->enable_count) {
- __clk_disable(parent);
- __clk_enable(old_parent);
- }
-
- clk_enable_unlock(flags);
-
- if (clk->prepare_count)
- __clk_unprepare(parent);
-
- return ret;
- }
-
- /* clean up enable for old parent if migration was done */
- if (migrated_enable) {
- flags = clk_enable_lock();
- __clk_disable(old_parent);
- clk_enable_unlock(flags);
- }
-
- /* clean up prepare for old parent if migration was done */
- if (clk->prepare_count)
- __clk_unprepare(old_parent);
-
- /* update debugfs with new clk tree topology */
- clk_debug_reparent(clk, parent);
- return 0;
-}
-
/**
* clk_set_parent - switch the parent of a mux clk
* @clk: the mux clk whose input we are switching
@@ -1546,8 +1677,9 @@ int __clk_init(struct device *dev, struct clk *clk)
/* check that clk_ops are sane. See Documentation/clk.txt */
if (clk->ops->set_rate &&
- !(clk->ops->round_rate && clk->ops->recalc_rate)) {
- pr_warning("%s: %s must implement .round_rate & .recalc_rate\n",
+ !((clk->ops->round_rate || clk->ops->determine_rate) &&
+ clk->ops->recalc_rate)) {
+ pr_warning("%s: %s must implement .round_rate or .determine_rate in addition to .recalc_rate\n",
__func__, clk->name);
ret = -EINVAL;
goto out;
diff --git a/drivers/clk/hisilicon/Kconfig b/drivers/clk/hisilicon/Kconfig
new file mode 100644
index 000000000000..1f8b3d3a2ed6
--- /dev/null
+++ b/drivers/clk/hisilicon/Kconfig
@@ -0,0 +1,7 @@
+config HI3xxx_CLK_CORE
+ bool "Core clock driver of Hi3xxx Soc"
+ default y if COMMON_CLK
+
+config HI3620_CLK_MIPI_DSI
+ bool "MIPI DSI clock driver of Hi3620 SoC"
+ default y if COMMON_CLK && FB_HI3620
diff --git a/drivers/clk/hisilicon/Makefile b/drivers/clk/hisilicon/Makefile
new file mode 100644
index 000000000000..e25405e712d9
--- /dev/null
+++ b/drivers/clk/hisilicon/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_HI3xxx_CLK_CORE) += clk-hi3xxx.o clk-hi3716.o
+obj-$(CONFIG_HI3620_CLK_MIPI_DSI) += clk-hi3620-dsi.o
diff --git a/drivers/clk/hisilicon/clk-hi3620-dsi.c b/drivers/clk/hisilicon/clk-hi3620-dsi.c
new file mode 100644
index 000000000000..c89e8ff1aa81
--- /dev/null
+++ b/drivers/clk/hisilicon/clk-hi3620-dsi.c
@@ -0,0 +1,364 @@
+/*
+ * Hisilicon Hi3620 MIPI DSI clock driver
+ *
+ * Copyright (c) 2012-2013 Hisilicon Limited.
+ * Copyright (c) 2012-2013 Linaro Limited.
+ *
+ * Author: Haojian Zhuang <haojian.zhuang@linaro.org>
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/clk-provider.h>
+#include <linux/clk-private.h>
+#include <linux/clkdev.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/platform_data/hi3620-dsi.h>
+
+#define DSI_CLKMGR_CFG 0x908
+#define DSI_PHY_RSTZ 0x954
+
+enum {
+ HI3620_EDC,
+};
+
+struct clk_phy {
+ struct clk_hw hw;
+ void __iomem *reg_base;
+ unsigned int mult;
+ unsigned int div;
+};
+
+struct clk_esc {
+ struct clk_hw hw;
+ void __iomem *reg_base;
+ unsigned int div;
+};
+
+struct hs_clk {
+ void __iomem *edc;
+ spinlock_t lock;
+};
+
+static void __iomem __init *hi3620_init_clocks(struct device_node *np);
+
+static struct hs_clk hi3620_clk;
+
+struct phy_mult {
+ int mult;
+ int cp_current;
+ int lpf_ctrl;
+};
+
+static unsigned long clk_phy_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_phy *phy = container_of(hw, struct clk_phy, hw);
+ unsigned long long int rate;
+
+ if (!phy->div)
+ return 0;
+ rate = (unsigned long long int)parent_rate * phy->mult;
+ do_div(rate, phy->div);
+ return (unsigned long)rate;
+}
+
+static long clk_phy_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ struct clk_phy *phy = container_of(hw, struct clk_phy, hw);
+ struct clk *clk_parent;
+ unsigned long long int mult, new_rate;
+
+ clk_parent = __clk_get_parent(hw->clk);
+ *prate = __clk_get_rate(clk_parent);
+ mult = (unsigned long long int)rate * phy->div;
+ do_div(mult, *prate);
+ new_rate = *prate * mult;
+ do_div(new_rate, phy->div);
+ return (unsigned long)new_rate;
+}
+
+static int clk_phy_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_phy *phy = container_of(hw, struct clk_phy, hw);
+ void __iomem *base = phy->reg_base;
+ unsigned long long int mult;
+ unsigned char cp_current, lpf_ctrl;
+ int i;
+ struct phy_mult m[] = { {32, 0x6, 0x10}, {64, 0x6, 0x10},
+ {128, 0xc, 0x8}, {256, 0x4, 0x4},
+ {512, 0x0, 0x1}, {768, 0x1, 0x1},
+ {1000, 0x2, 0x1}, };
+ mult = (unsigned long long int)rate * phy->div;
+ do_div(mult, parent_rate);
+ phy->mult = (unsigned int)mult;
+
+ for (i = 0; i < ARRAY_SIZE(m); i++) {
+ if (phy->mult <= m[i].mult) {
+ cp_current = m[i].cp_current;
+ lpf_ctrl = m[i].lpf_ctrl;
+ break;
+ }
+ }
+ if (i >= ARRAY_SIZE(m))
+ return -EINVAL;
+ lpf_ctrl |= 0xc0; /* bypass CP & LPF default values */
+ /* write CP current */
+ hi3620_dsi_phy_write(base, 0x11, cp_current);
+ /* write LPF control */
+ hi3620_dsi_phy_write(base, 0x12, lpf_ctrl);
+ /* configure N and M factors effectively */
+ hi3620_dsi_phy_write(base, 0x19, 0x33);
+ /* write N divider */
+ hi3620_dsi_phy_write(base, 0x17, phy->div - 1);
+ /* write M multiplier 1 */
+ hi3620_dsi_phy_write(base, 0x18, (phy->mult - 1) & 0x1f);
+ /* write M multiplier 2 */
+ hi3620_dsi_phy_write(base, 0x18, ((phy->mult - 1) >> 5) | 0x80);
+ /* set PLL unlocking filter */
+ hi3620_dsi_phy_write(base, 0x16, 0xff);
+ return 0;
+}
+
+struct clk_ops clk_phy_ops = {
+ .round_rate = clk_phy_round_rate,
+ .set_rate = clk_phy_set_rate,
+ .recalc_rate = clk_phy_recalc_rate,
+};
+
+static struct clk *clk_phy_register(struct device *dev, const char *name,
+ const char *parent_name, void __iomem *reg,
+ unsigned long flags)
+{
+ struct clk_phy *phy;
+ struct clk_init_data init;
+ struct clk *clk;
+
+ phy = kzalloc(sizeof(*phy), GFP_KERNEL);
+ if (!phy) {
+ pr_err("%s: could not allocate dsi phy clk\n", __func__);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ /* struct clk_phy assignments */
+ phy->hw.init = &init;
+ phy->div = 13; /* since parent rate is always 26MHz */
+ phy->reg_base = reg;
+
+ init.name = name;
+ init.ops = &clk_phy_ops;
+ init.flags = flags | CLK_IS_BASIC;
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+
+ clk = clk_register(dev, &phy->hw);
+
+ if (IS_ERR(clk))
+ kfree(phy);
+
+ return clk;
+}
+
+void __init hi3620_phy_setup(struct device_node *np)
+{
+ struct clk *clk;
+ const char *clk_name, **parent_names;
+ void __iomem *reg_base;
+
+ reg_base = hi3620_init_clocks(np);
+ if (!reg_base)
+ return;
+ if (of_property_read_string(np, "clock-output-names", &clk_name))
+ return;
+ /* gate only has the fixed parent */
+ parent_names = kzalloc(sizeof(char *), GFP_KERNEL);
+ if (!parent_names)
+ return;
+ parent_names[0] = of_clk_get_parent_name(np, 0);
+
+ clk = clk_phy_register(NULL, clk_name, parent_names[0], reg_base, 0);
+ if (IS_ERR(clk))
+ goto err;
+ of_clk_add_provider(np, of_clk_src_simple_get, clk);
+ return;
+err:
+ kfree(parent_names);
+}
+
+static int find_best_esc_divider(unsigned long parent_rate)
+{
+ unsigned int max_rate = 20000000; /* 20MHz */
+ unsigned int target_rate = 10000000; /* 10MHz */
+ unsigned int div, out_rate;
+
+ div = parent_rate / target_rate;
+ for (; div > 0; div--) {
+ out_rate = parent_rate / div;
+ if (out_rate < max_rate)
+ break;
+ }
+ if (div <= 0)
+ return 0;
+ return div;
+}
+
+static unsigned long clk_esc_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_esc *esc = container_of(hw, struct clk_esc, hw);
+ unsigned int div;
+
+ if (!esc->div)
+ div = find_best_esc_divider(parent_rate);
+ else
+ div = esc->div;
+ if (!div)
+ return 0;
+ return parent_rate / div;
+}
+
+static long clk_esc_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ struct clk *clk_parent;
+ unsigned int div;
+
+ clk_parent = __clk_get_parent(hw->clk);
+ *prate = __clk_get_rate(clk_parent);
+
+ div = find_best_esc_divider(*prate);
+ return *prate / div;
+}
+
+static int clk_esc_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_esc *esc = container_of(hw, struct clk_esc, hw);
+ unsigned int data;
+
+ esc->div = parent_rate / rate;
+ data = readl_relaxed(esc->reg_base + DSI_CLKMGR_CFG);
+ data &= ~0xff;
+ writel_relaxed(data | esc->div, esc->reg_base + DSI_CLKMGR_CFG);
+ return 0;
+}
+
+struct clk_ops clk_esc_ops = {
+ .round_rate = clk_esc_round_rate,
+ .set_rate = clk_esc_set_rate,
+ .recalc_rate = clk_esc_recalc_rate,
+};
+
+static struct clk *clk_esc_register(struct device *dev, const char *name,
+ const char *parent_name, void __iomem *reg,
+ unsigned long flags)
+{
+ struct clk_esc *esc;
+ struct clk_init_data init;
+ struct clk *clk;
+
+ esc = kzalloc(sizeof(*esc), GFP_KERNEL);
+ if (!esc) {
+ pr_err("%s: could not allocate dsi esc clk\n", __func__);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ /* struct clk_esc assignments */
+ esc->hw.init = &init;
+ esc->reg_base = reg;
+
+ init.name = name;
+ init.ops = &clk_esc_ops;
+ init.flags = flags | CLK_IS_BASIC;
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+
+ clk = clk_register(dev, &esc->hw);
+
+ if (IS_ERR(clk))
+ kfree(esc);
+
+ return clk;
+}
+
+void __init hi3620_esc_setup(struct device_node *np)
+{
+ struct clk *clk;
+ const char *clk_name, **parent_names;
+ void __iomem *reg_base;
+
+ reg_base = hi3620_init_clocks(np);
+ if (!reg_base)
+ return;
+ if (of_property_read_string(np, "clock-output-names", &clk_name))
+ return;
+ /* gate only has the fixed parent */
+ parent_names = kzalloc(sizeof(char *), GFP_KERNEL);
+ if (!parent_names)
+ return;
+ parent_names[0] = of_clk_get_parent_name(np, 0);
+
+ clk = clk_esc_register(NULL, clk_name, parent_names[0], reg_base, 0);
+ if (IS_ERR(clk))
+ goto err;
+ of_clk_add_provider(np, of_clk_src_simple_get, clk);
+ return;
+err:
+ kfree(parent_names);
+}
+
+CLK_OF_DECLARE(hi3620_dsi_pll, "hisilicon,hi3620-phy", hi3620_phy_setup)
+CLK_OF_DECLARE(hi3620_dsi_esc, "hisilicon,hi3620-phy-esc", hi3620_esc_setup)
+
+static const struct of_device_id hi3620_of_match[] = {
+ { .compatible = "hisilicon,hi3620-fb", .data = (void *)HI3620_EDC, },
+};
+
+static void __iomem __init *hi3620_init_clocks(struct device_node *np)
+{
+ struct device_node *parent;
+ const struct of_device_id *match;
+ void __iomem *ret = NULL;
+
+ parent = of_get_parent(np);
+ if (!parent)
+ goto out;
+ match = of_match_node(hi3620_of_match, parent);
+ if (!match)
+ goto out;
+ switch ((unsigned int)match->data) {
+ case HI3620_EDC:
+ if (!hi3620_clk.edc) {
+ ret = of_iomap(parent, 0);
+ WARN_ON(!ret);
+ hi3620_clk.edc = ret;
+ } else {
+ ret = hi3620_clk.edc;
+ }
+ break;
+ }
+out:
+ return ret;
+}
diff --git a/drivers/clk/hisilicon/clk-hi3716.c b/drivers/clk/hisilicon/clk-hi3716.c
new file mode 100644
index 000000000000..887ffe90fba5
--- /dev/null
+++ b/drivers/clk/hisilicon/clk-hi3716.c
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 2013 Linaro Ltd.
+ * Copyright (c) 2013 Hisilicon Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+
+static DEFINE_SPINLOCK(_lock);
+
+static void __iomem *clk_base;
+
+struct hi3716_clk {
+ struct clk_gate gate;
+ void __iomem *reg;
+ u8 reset_bit;
+};
+
+#define MAX_NUMS 10
+
+static struct hi3716_clk *to_clk_hi3716(struct clk_hw *hw)
+{
+ return container_of(hw, struct hi3716_clk, gate.hw);
+}
+
+static void __init hi3716_map_io(void)
+{
+ struct device_node *node;
+
+ if (clk_base)
+ return;
+
+ node = of_find_compatible_node(NULL, NULL, "hisilicon,clkbase");
+ if (node)
+ clk_base = of_iomap(node, 0);
+ WARN_ON(!clk_base);
+}
+
+static int hi3716_clkgate_prepare(struct clk_hw *hw)
+{
+ struct hi3716_clk *clk = to_clk_hi3716(hw);
+ unsigned long flags = 0;
+ u32 reg;
+
+ spin_lock_irqsave(&_lock, flags);
+
+ reg = readl_relaxed(clk->reg);
+ reg &= ~BIT(clk->reset_bit);
+ writel_relaxed(reg, clk->reg);
+
+ spin_unlock_irqrestore(&_lock, flags);
+
+ return 0;
+}
+
+static void hi3716_clkgate_unprepare(struct clk_hw *hw)
+{
+ struct hi3716_clk *clk = to_clk_hi3716(hw);
+ unsigned long flags = 0;
+ u32 reg;
+
+ spin_lock_irqsave(&_lock, flags);
+
+ reg = readl_relaxed(clk->reg);
+ reg |= BIT(clk->reset_bit);
+ writel_relaxed(reg, clk->reg);
+
+ spin_unlock_irqrestore(&_lock, flags);
+}
+
+static struct clk_ops hi3716_clkgate_ops = {
+ .prepare = hi3716_clkgate_prepare,
+ .unprepare = hi3716_clkgate_unprepare,
+};
+
+void __init hi3716_clkgate_setup(struct device_node *node)
+{
+ struct clk *clk;
+ struct hi3716_clk *p_clk;
+ struct clk_init_data init;
+ const char *parent_name;
+ u32 array[3]; /* reg, enable_bit, reset_bit */
+ int err;
+
+ hi3716_map_io();
+ err = of_property_read_u32_array(node, "gate-reg", &array[0], 3);
+ if (WARN_ON(err))
+ return;
+
+ err = of_property_read_string(node, "clock-output-names", &init.name);
+ if (WARN_ON(err))
+ return;
+
+ p_clk = kzalloc(sizeof(*p_clk), GFP_KERNEL);
+ if (WARN_ON(!p_clk))
+ return;
+
+ hi3716_clkgate_ops.enable = clk_gate_ops.enable;
+ hi3716_clkgate_ops.disable = clk_gate_ops.disable;
+ hi3716_clkgate_ops.is_enabled = clk_gate_ops.is_enabled;
+
+ init.ops = &hi3716_clkgate_ops;
+ init.flags = CLK_SET_RATE_PARENT;
+ parent_name = of_clk_get_parent_name(node, 0);
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+
+ p_clk->reg = p_clk->gate.reg = clk_base + array[0];
+ p_clk->gate.bit_idx = array[1];
+ p_clk->gate.flags = 0;
+ p_clk->gate.lock = &_lock;
+ p_clk->gate.hw.init = &init;
+ p_clk->reset_bit = array[2];
+
+ clk = clk_register(NULL, &p_clk->gate.hw);
+ if (WARN_ON(IS_ERR(clk))) {
+ kfree(p_clk);
+ return;
+ }
+
+ of_clk_add_provider(node, of_clk_src_simple_get, clk);
+}
+
+static void __init hi3716_clkmux_setup(struct device_node *node)
+{
+ int num = 0, err;
+ void __iomem *reg;
+ unsigned int shift, width;
+ u32 array[3]; /* reg, mux_shift, mux_width */
+ u32 *table = NULL;
+ const char *clk_name = node->name;
+ const char *parents[MAX_NUMS];
+ struct clk *clk;
+
+ hi3716_map_io();
+ err = of_property_read_string(node, "clock-output-names", &clk_name);
+ if (WARN_ON(err))
+ return;
+
+ err = of_property_read_u32_array(node, "mux-reg", &array[0], 3);
+ if (WARN_ON(err))
+ return;
+
+ reg = clk_base + array[0];
+ shift = array[1];
+ width = array[2];
+
+ while ((num < MAX_NUMS) &&
+ ((parents[num] = of_clk_get_parent_name(node, num)) != NULL))
+ num++;
+ if (!num)
+ return;
+
+ table = kzalloc(sizeof(u32 *) * num, GFP_KERNEL);
+ if (WARN_ON(!table))
+ return;
+
+ err = of_property_read_u32_array(node, "mux-table", table, num);
+ if (WARN_ON(err))
+ goto err;
+
+ clk = clk_register_mux_table(NULL, clk_name, parents, num,
+ CLK_SET_RATE_PARENT, reg, shift, BIT(width) - 1,
+ 0, table, &_lock);
+ if (WARN_ON(IS_ERR(clk)))
+ goto err;
+
+ clk_register_clkdev(clk, clk_name, NULL);
+ of_clk_add_provider(node, of_clk_src_simple_get, clk);
+ return;
+
+err:
+ kfree(table);
+ return;
+}
+
+static void __init hi3716_fixed_pll_setup(struct device_node *node)
+{
+ const char *clk_name, *parent_name;
+ struct clk *clks[MAX_NUMS];
+ u32 rate[MAX_NUMS];
+ struct clk_onecell_data *clk_data;
+ int i, err, nums = 0;
+
+ nums = of_property_count_strings(node, "clock-output-names");
+ if (WARN_ON((nums < 0) || (nums > MAX_NUMS)))
+ return;
+
+ err = of_property_read_u32_array(node, "clock-frequency",
+ &rate[0], nums);
+ WARN_ON(err);
+
+ parent_name = of_clk_get_parent_name(node, 0);
+
+ for (i = 0; i < nums; i++) {
+ err = of_property_read_string_index(node, "clock-output-names",
+ i, &clk_name);
+ WARN_ON(err);
+
+ clks[i] = clk_register_fixed_rate(NULL, clk_name,
+ parent_name, 0, rate[i]);
+ WARN_ON(IS_ERR(clks[i]));
+ }
+
+ clk_data = kzalloc(sizeof(*clk_data) + nums * sizeof(struct clk *),
+ GFP_KERNEL);
+ if (WARN_ON(!clk_data))
+ return;
+
+ memcpy(&clk_data[1], clks, nums * sizeof(struct clk *));
+ clk_data->clks = (struct clk **)&clk_data[1];
+ clk_data->clk_num = nums;
+ of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+}
+
+void __init hi3716_fixed_divider_setup(struct device_node *node)
+{
+ const char *clk_parent;
+ const char *clk_name;
+ u32 div[MAX_NUMS];
+ struct clk *clks[MAX_NUMS];
+ struct clk_onecell_data *clk_data;
+ int err, i, nums = 0;
+
+ clk_parent = of_clk_get_parent_name(node, 0);
+
+ nums = of_property_count_strings(node, "clock-output-names");
+ if (WARN_ON((nums < 0) || (nums > MAX_NUMS)))
+ return;
+
+ err = of_property_read_u32_array(node, "div-table", &div[0], nums);
+ WARN_ON(err);
+
+ for (i = 0; i < nums; i++) {
+ err = of_property_read_string_index(node,
+ "clock-output-names", i, &clk_name);
+ WARN_ON(err);
+
+ clks[i] = clk_register_fixed_factor(NULL, clk_name,
+ clk_parent, CLK_SET_RATE_PARENT, 1, div[i]);
+ WARN_ON(IS_ERR(clks[i]));
+ }
+
+ clk_data = kzalloc(sizeof(*clk_data) + nums * sizeof(struct clk *),
+ GFP_KERNEL);
+ if (WARN_ON(!clk_data))
+ return;
+
+ memcpy(&clk_data[1], clks, nums * sizeof(struct clk *));
+ clk_data->clks = (struct clk **)&clk_data[1];
+ clk_data->clk_num = nums;
+ of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+}
+
+CLK_OF_DECLARE(hi3716_fixed_rate, "fixed-clock", of_fixed_clk_setup)
+CLK_OF_DECLARE(hi3716_fixed_pll, "hisilicon,hi3716-fixed-pll", hi3716_fixed_pll_setup)
+CLK_OF_DECLARE(hi3716_divider, "hisilicon,hi3716-fixed-divider", hi3716_fixed_divider_setup)
+CLK_OF_DECLARE(hi3716_mux, "hisilicon,hi3716-clk-mux", hi3716_clkmux_setup)
+CLK_OF_DECLARE(hi3716_gate, "hisilicon,hi3716-clk-gate", hi3716_clkgate_setup)
diff --git a/drivers/clk/hisilicon/clk-hi3xxx.c b/drivers/clk/hisilicon/clk-hi3xxx.c
new file mode 100644
index 000000000000..d3969a3ea5c8
--- /dev/null
+++ b/drivers/clk/hisilicon/clk-hi3xxx.c
@@ -0,0 +1,641 @@
+/*
+ * Hisilicon clock driver
+ *
+ * Copyright (c) 2012-2013 Hisilicon Limited.
+ * Copyright (c) 2012-2013 Linaro Limited.
+ *
+ * Author: Haojian Zhuang <haojian.zhuang@linaro.org>
+ * Xin Li <li.xin@linaro.org>
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/clk-provider.h>
+#include <linux/clk-private.h>
+#include <linux/clkdev.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+
+#define HI3620_DISABLE_OFF 0x4
+#define HI3620_STATUS_OFF 0x8
+
+#define WIDTH_TO_MASK(width) ((1 << (width)) - 1)
+
+/*
+ * The reverse of DIV_ROUND_UP: The maximum number which
+ * divided by m is r
+ */
+#define MULT_ROUND_UP(r, m) ((r) * (m) + (m) - 1)
+
+enum {
+ HS_PMCTRL,
+ HS_SYSCTRL,
+ HS_EDC,
+};
+
+struct hi3620_periclk {
+ struct clk_hw hw;
+ void __iomem *enable; /* enable register */
+ void __iomem *reset; /* reset register */
+ u32 ebits; /* bits in enable/disable register */
+ u32 rbits; /* bits in reset/unreset register */
+ spinlock_t *lock;
+};
+
+struct hi3620_muxclk {
+ struct clk_hw hw;
+ void __iomem *reg; /* mux register */
+ u8 shift;
+ u8 width;
+ u32 mbits; /* mask bits in mux register */
+ spinlock_t *lock;
+};
+
+struct hi3620_divclk {
+ struct clk_hw hw;
+ void __iomem *reg; /* divider register */
+ u8 shift;
+ u8 width;
+ u32 mbits; /* mask bits in divider register */
+ const struct clk_div_table *table;
+ spinlock_t *lock;
+};
+
+struct hs_clk {
+ void __iomem *pmctrl;
+ void __iomem *sctrl;
+ void __iomem *edc;
+ spinlock_t lock;
+};
+
+static void __iomem __init *hs_init_clocks(struct device_node *np);
+
+static struct hs_clk hs_clk =
+{
+ .lock = __SPIN_LOCK_UNLOCKED(hs_clk.lock),
+};
+
+static int hi3620_clkgate_prepare(struct clk_hw *hw)
+{
+ struct hi3620_periclk *pclk;
+ unsigned long flags = 0;
+
+ pclk = container_of(hw, struct hi3620_periclk, hw);
+
+ if (pclk->lock)
+ spin_lock_irqsave(pclk->lock, flags);
+ if (pclk->reset) {
+ writel_relaxed(pclk->rbits, pclk->reset + HI3620_DISABLE_OFF);
+ readl_relaxed(pclk->reset + HI3620_STATUS_OFF);
+ }
+ if (pclk->lock)
+ spin_unlock_irqrestore(pclk->lock, flags);
+ return 0;
+}
+
+static int hi3620_clkgate_enable(struct clk_hw *hw)
+{
+ struct hi3620_periclk *pclk;
+ unsigned long flags = 0;
+
+ pclk = container_of(hw, struct hi3620_periclk, hw);
+ if (pclk->lock)
+ spin_lock_irqsave(pclk->lock, flags);
+ writel_relaxed(pclk->ebits, pclk->enable);
+ readl_relaxed(pclk->enable + HI3620_STATUS_OFF);
+ if (pclk->lock)
+ spin_unlock_irqrestore(pclk->lock, flags);
+ return 0;
+}
+
+static void hi3620_clkgate_disable(struct clk_hw *hw)
+{
+ struct hi3620_periclk *pclk;
+ unsigned long flags = 0;
+
+ pclk = container_of(hw, struct hi3620_periclk, hw);
+ if (pclk->lock)
+ spin_lock_irqsave(pclk->lock, flags);
+ writel_relaxed(pclk->ebits, pclk->enable + HI3620_DISABLE_OFF);
+ readl_relaxed(pclk->enable + HI3620_STATUS_OFF);
+ if (pclk->lock)
+ spin_unlock_irqrestore(pclk->lock, flags);
+}
+
+static struct clk_ops hi3620_clkgate_ops = {
+ .prepare = hi3620_clkgate_prepare,
+ .enable = hi3620_clkgate_enable,
+ .disable = hi3620_clkgate_disable,
+};
+
+static void __init hi3620_clkgate_setup(struct device_node *np)
+{
+ struct hi3620_periclk *pclk;
+ struct clk_init_data *init;
+ struct clk *clk;
+ const char *clk_name, *name, **parent_names;
+ void __iomem *reg_base;
+ u32 rdata[2], gdata[2];
+
+ reg_base = hs_init_clocks(np);
+ if (!reg_base)
+ return;
+
+ if (of_property_read_string(np, "clock-output-names", &clk_name))
+ return;
+ if (of_property_read_u32_array(np, "hisilicon,hi3620-clkgate",
+ &gdata[0], 2))
+ return;
+
+ /* gate only has the fixed parent */
+ parent_names = kzalloc(sizeof(char *), GFP_KERNEL);
+ if (!parent_names)
+ return;
+ parent_names[0] = of_clk_get_parent_name(np, 0);
+
+ pclk = kzalloc(sizeof(*pclk), GFP_KERNEL);
+ if (!pclk)
+ goto err_pclk;
+
+ init = kzalloc(sizeof(*init), GFP_KERNEL);
+ if (!init)
+ goto err_init;
+ init->name = kstrdup(clk_name, GFP_KERNEL);
+ init->ops = &hi3620_clkgate_ops;
+ init->flags = CLK_SET_RATE_PARENT;
+ init->parent_names = parent_names;
+ init->num_parents = 1;
+
+ if (of_property_read_u32_array(np, "hisilicon,hi3620-clkreset",
+ &rdata[0], 2)) {
+ pclk->reset = 0;
+ pclk->rbits = 0;
+ } else {
+ pclk->reset = reg_base + rdata[0];
+ pclk->rbits = rdata[1];
+ }
+ pclk->enable = reg_base + gdata[0];
+ pclk->ebits = gdata[1];
+ pclk->lock = &hs_clk.lock;
+ pclk->hw.init = init;
+
+ clk = clk_register(NULL, &pclk->hw);
+ if (IS_ERR(clk))
+ goto err_clk;
+ if (!of_property_read_string(np, "clock-output-names", &name))
+ clk_register_clkdev(clk, name, NULL);
+ of_clk_add_provider(np, of_clk_src_simple_get, clk);
+ return;
+err_clk:
+ kfree(init);
+err_init:
+ kfree(pclk);
+err_pclk:
+ kfree(parent_names);
+}
+
+static void __init hi3620_clkmux_setup(struct device_node *np)
+{
+ struct clk *clk;
+ const char *clk_name, **parent_names = NULL;
+ u32 rdata[2], mask, *table = NULL;
+ u8 shift, flag = 0;
+ void __iomem *reg, *base;
+ int i, cnt, ret;
+
+ base = hs_init_clocks(np);
+ if (!base)
+ return;
+
+ if (of_property_read_string(np, "clock-output-names", &clk_name))
+ return;
+ if (of_property_read_u32_array(np, "hisilicon,clkmux-reg",
+ &rdata[0], 2))
+ return;
+
+ if (of_property_read_bool(np, "hiword"))
+ flag = CLK_MUX_HIWORD_MASK;
+
+ cnt = of_count_phandle_with_args(np, "clocks", "#clock-cells");
+ if (cnt < 0) {
+ pr_err("failed to find clock parent\n");
+ return;
+ }
+
+ table = kzalloc(sizeof(u32) * cnt, GFP_KERNEL);
+ if (!table)
+ return;
+ ret = of_property_read_u32_array(np, "hisilicon,clkmux-table",
+ table, cnt);
+ if (ret) {
+ pr_err("failed on parsing %s's clkmux-table \n", clk_name);
+ return;
+ }
+
+ parent_names = kzalloc(sizeof(char *) * cnt, GFP_KERNEL);
+ if (!parent_names)
+ goto err;
+ for (i = 0; i < cnt; i++)
+ parent_names[i] = of_clk_get_parent_name(np, i);
+
+ reg = base + rdata[0];
+ shift = ffs(rdata[1]) - 1;
+ mask = rdata[1] >> shift;
+ clk = clk_register_mux_table(NULL, clk_name, parent_names, (u8)cnt,
+ CLK_SET_RATE_PARENT, reg, shift, mask,
+ flag, table,
+ &hs_clk.lock);
+ if (IS_ERR(clk))
+ goto err_clk;
+ of_clk_add_provider(np, of_clk_src_simple_get, clk);
+
+ return;
+err_clk:
+ kfree(parent_names);
+err:
+ kfree(table);
+}
+CLK_OF_DECLARE(hi3620_mux, "hisilicon,hi3620-clk-mux", hi3620_clkmux_setup)
+
+static void __init hs_clkgate_setup(struct device_node *np)
+{
+ struct clk *clk;
+ const char *clk_name, **parent_names, *name;
+ unsigned long flags = 0;
+ void __iomem *reg_base;
+ u32 data[2];
+
+ reg_base = hs_init_clocks(np);
+ if (!reg_base)
+ return;
+ if (of_property_read_string(np, "clock-output-names", &clk_name))
+ return;
+ if (of_property_read_u32_array(np, "hisilicon,clkgate",
+ &data[0], 2))
+ return;
+ if (of_property_read_bool(np, "hisilicon,clkgate-inverted"))
+ flags = CLK_GATE_SET_TO_DISABLE;
+ if (of_property_read_bool(np, "hiword"))
+ flags |= CLK_GATE_HIWORD_MASK;
+ /* gate only has the fixed parent */
+ parent_names = kzalloc(sizeof(char *), GFP_KERNEL);
+ if (!parent_names)
+ return;
+ parent_names[0] = of_clk_get_parent_name(np, 0);
+
+ clk = clk_register_gate(NULL, clk_name, parent_names[0],
+ CLK_SET_RATE_PARENT, reg_base + data[0],
+ (u8)data[1], flags, &hs_clk.lock);
+ if (IS_ERR(clk))
+ goto err;
+ if (!of_property_read_string(np, "clock-names", &name))
+ clk_register_clkdev(clk, name, NULL);
+ of_clk_add_provider(np, of_clk_src_simple_get, clk);
+ return;
+err:
+ kfree(parent_names);
+}
+
+void __init hs_fixed_factor_setup(struct device_node *np)
+{
+ struct clk *clk;
+ const char *clk_name, **parent_names;
+ u32 data[2];
+
+ if (of_property_read_string(np, "clock-output-names", &clk_name))
+ return;
+ if (of_property_read_u32_array(np, "hisilicon,fixed-factor",
+ data, 2))
+ return ;
+ /* gate only has the fixed parent */
+ parent_names = kzalloc(sizeof(char *), GFP_KERNEL);
+ if (!parent_names)
+ return;
+ parent_names[0] = of_clk_get_parent_name(np, 0);
+
+ clk = clk_register_fixed_factor(NULL, clk_name, parent_names[0],
+ CLK_SET_RATE_PARENT,
+ data[0], data[1]);
+ if (IS_ERR(clk))
+ goto err;
+ of_clk_add_provider(np, of_clk_src_simple_get, clk);
+ return;
+err:
+ kfree(parent_names);
+}
+
+static unsigned int hi3620_get_table_maxdiv(const struct clk_div_table *table)
+{
+ unsigned int maxdiv = 0;
+ const struct clk_div_table *clkt;
+
+ for (clkt = table; clkt->div; clkt++)
+ if (clkt->div > maxdiv)
+ maxdiv = clkt->div;
+ return maxdiv;
+}
+
+static unsigned int hi3620_get_table_div(const struct clk_div_table *table,
+ unsigned int val)
+{
+ const struct clk_div_table *clkt;
+
+ for (clkt = table; clkt->div; clkt++)
+ if (clkt->val == val)
+ return clkt->div;
+ return 0;
+}
+
+static unsigned int hi3620_get_table_val(const struct clk_div_table *table,
+ unsigned int div)
+{
+ const struct clk_div_table *clkt;
+
+ for (clkt = table; clkt->div; clkt++)
+ if (clkt->div == div)
+ return clkt->val;
+ return 0;
+}
+
+static unsigned long hi3620_clkdiv_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct hi3620_divclk *dclk = container_of(hw, struct hi3620_divclk, hw);
+ unsigned int div, val;
+
+ val = readl_relaxed(dclk->reg) >> dclk->shift;
+ val &= WIDTH_TO_MASK(dclk->width);
+
+ div = hi3620_get_table_div(dclk->table, val);
+ if (!div) {
+ pr_warning("%s: Invalid divisor for clock %s\n", __func__,
+ __clk_get_name(hw->clk));
+ return parent_rate;
+ }
+
+ return parent_rate / div;
+}
+
+static bool hi3620_is_valid_table_div(const struct clk_div_table *table,
+ unsigned int div)
+{
+ const struct clk_div_table *clkt;
+
+ for (clkt = table; clkt->div; clkt++)
+ if (clkt->div == div)
+ return true;
+ return false;
+}
+
+static int hi3620_clkdiv_bestdiv(struct clk_hw *hw, unsigned long rate,
+ unsigned long *best_parent_rate)
+{
+ struct hi3620_divclk *dclk = container_of(hw, struct hi3620_divclk, hw);
+ struct clk *clk_parent = __clk_get_parent(hw->clk);
+ int i, bestdiv = 0;
+ unsigned long parent_rate, best = 0, now, maxdiv;
+
+ maxdiv = hi3620_get_table_maxdiv(dclk->table);
+
+ if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) {
+ parent_rate = *best_parent_rate;
+ bestdiv = DIV_ROUND_UP(parent_rate, rate);
+ bestdiv = bestdiv == 0 ? 1 : bestdiv;
+ bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv;
+ return bestdiv;
+ }
+
+ /*
+ * The maximum divider we can use without overflowing
+ * unsigned long in rate * i below
+ */
+ maxdiv = min(ULONG_MAX / rate, maxdiv);
+
+ for (i = 1; i <= maxdiv; i++) {
+ if (!hi3620_is_valid_table_div(dclk->table, i))
+ continue;
+ parent_rate = __clk_round_rate(clk_parent,
+ MULT_ROUND_UP(rate, i));
+ now = parent_rate / i;
+ if (now <= rate && now > best) {
+ bestdiv = i;
+ best = now;
+ *best_parent_rate = parent_rate;
+ }
+ }
+
+ if (!bestdiv) {
+ bestdiv = hi3620_get_table_maxdiv(dclk->table);
+ *best_parent_rate = __clk_round_rate(clk_parent, 1);
+ }
+
+ return bestdiv;
+}
+
+static long hi3620_clkdiv_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ int div;
+
+ if (!rate)
+ rate = 1;
+ div = hi3620_clkdiv_bestdiv(hw, rate, prate);
+
+ return *prate / div;
+}
+
+static int hi3620_clkdiv_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct hi3620_divclk *dclk = container_of(hw, struct hi3620_divclk, hw);
+ unsigned int div, value;
+ unsigned long flags = 0;
+ u32 data;
+
+ div = parent_rate / rate;
+ value = hi3620_get_table_val(dclk->table, div);
+
+ if (value > WIDTH_TO_MASK(dclk->width))
+ value = WIDTH_TO_MASK(dclk->width);
+
+ if (dclk->lock)
+ spin_lock_irqsave(dclk->lock, flags);
+
+ data = readl_relaxed(dclk->reg);
+ data &= ~(WIDTH_TO_MASK(dclk->width) << dclk->shift);
+ data |= value << dclk->shift;
+ data |= dclk->mbits;
+ writel_relaxed(data, dclk->reg);
+
+ if (dclk->lock)
+ spin_unlock_irqrestore(dclk->lock, flags);
+
+ return 0;
+}
+
+static struct clk_ops hi3620_clkdiv_ops = {
+ .recalc_rate = hi3620_clkdiv_recalc_rate,
+ .round_rate = hi3620_clkdiv_round_rate,
+ .set_rate = hi3620_clkdiv_set_rate,
+};
+
+void __init hi3620_clkdiv_setup(struct device_node *np)
+{
+ struct clk *clk;
+ const char *clk_name, **parent_names;
+ struct clk_init_data *init;
+ struct clk_div_table *table;
+ struct hi3620_divclk *dclk;
+ void __iomem *reg_base;
+ unsigned int table_num;
+ int i;
+ u32 data[2];
+ unsigned int max_div, min_div;
+ struct of_phandle_args div_table;
+
+ reg_base = hs_init_clocks(np);
+ if (!reg_base)
+ return;
+
+ if (of_property_read_string(np, "clock-output-names", &clk_name))
+ return;
+
+ /*process the div_table*/
+ if (of_property_read_u32_array(np, "hisilicon,clkdiv-table",
+ &data[0], 2))
+ return;
+
+ max_div = (u8)data[0];
+ min_div = (u8)data[1];
+
+ if (of_property_read_u32_array(np, "hisilicon,clkdiv",
+ &data[0], 2))
+ return;
+
+ /*table ends with <0, 0>, so plus one to table_num*/
+ table_num = max_div - min_div + 1 + 1;
+
+ table = kzalloc(sizeof(struct clk_div_table) * table_num, GFP_KERNEL);
+ if (!table)
+ return ;
+
+ for (i = 0; i < table_num; i++) {
+ table[i].div = min_div + i;
+ table[i].val = table[i].div - 1;
+ }
+
+ /* gate only has the fixed parent */
+ parent_names = kzalloc(sizeof(char *), GFP_KERNEL);
+ if (!parent_names)
+ goto err_par;
+ parent_names[0] = of_clk_get_parent_name(np, 0);
+
+ dclk = kzalloc(sizeof(*dclk), GFP_KERNEL);
+ if (!dclk)
+ goto err_dclk;
+ init = kzalloc(sizeof(*init), GFP_KERNEL);
+ if (!init)
+ goto err_init;
+ init->name = kstrdup(clk_name, GFP_KERNEL);
+ init->ops = &hi3620_clkdiv_ops;
+ init->parent_names = parent_names;
+ init->num_parents = 1;
+
+ dclk->reg = reg_base + data[0];
+ dclk->shift = ffs(data[1]) - 1;
+ dclk->width = fls(data[1]) - ffs(data[1]) + 1;
+ dclk->mbits = data[1] << 16;
+ dclk->lock = &hs_clk.lock;
+ dclk->hw.init = init;
+ dclk->table = table;
+ clk = clk_register(NULL, &dclk->hw);
+ if (IS_ERR(clk))
+ goto err_clk;
+ of_clk_add_provider(np, of_clk_src_simple_get, clk);
+ clk_register_clkdev(clk, clk_name, NULL);
+ return;
+err_clk:
+ kfree(init);
+err_init:
+ kfree(dclk);
+err_dclk:
+ kfree(parent_names);
+err_par:
+ kfree(table);
+}
+
+CLK_OF_DECLARE(hi3620_fixed_rate, "fixed-clock", of_fixed_clk_setup)
+CLK_OF_DECLARE(hi3620_div, "hisilicon,hi3620-clk-div", hi3620_clkdiv_setup)
+CLK_OF_DECLARE(hs_gate, "hisilicon,clk-gate", hs_clkgate_setup)
+CLK_OF_DECLARE(hs_fixed, "hisilicon,clk-fixed-factor", hs_fixed_factor_setup)
+CLK_OF_DECLARE(hi3620_gate, "hisilicon,hi3620-clk-gate", hi3620_clkgate_setup)
+
+static const struct of_device_id hs_of_match[] = {
+ { .compatible = "hisilicon,pmctrl", .data = (void *)HS_PMCTRL, },
+ { .compatible = "hisilicon,sctrl", .data = (void *)HS_SYSCTRL, },
+ { .compatible = "hisilicon,hi3620-fb", .data = (void *)HS_EDC, },
+};
+
+static void __iomem __init *hs_init_clocks(struct device_node *np)
+{
+ struct device_node *parent;
+ const struct of_device_id *match;
+ void __iomem *ret = NULL;
+
+ parent = of_get_parent(np);
+ if (!parent)
+ goto out;
+ match = of_match_node(hs_of_match, parent);
+ if (!match)
+ goto out;
+ switch ((unsigned int)match->data) {
+ case HS_PMCTRL:
+ if (!hs_clk.pmctrl) {
+ ret = of_iomap(parent, 0);
+ WARN_ON(!ret);
+ hs_clk.pmctrl = ret;
+ } else {
+ ret = hs_clk.pmctrl;
+ }
+ break;
+ case HS_SYSCTRL:
+ if (!hs_clk.sctrl) {
+ ret = of_iomap(parent, 0);
+ WARN_ON(!ret);
+ hs_clk.sctrl = ret;
+ } else {
+ ret = hs_clk.sctrl;
+ }
+ break;
+ case HS_EDC:
+ if (!hs_clk.edc) {
+ ret = of_iomap(parent, 0);
+ WARN_ON(!ret);
+ hs_clk.edc = ret;
+ } else {
+ ret = hs_clk.edc;
+ }
+ break;
+ }
+out:
+ return ret;
+}
diff --git a/drivers/clk/mmp/clk-mmp2.c b/drivers/clk/mmp/clk-mmp2.c
index d1f1a19d4351..b2721cae257a 100644
--- a/drivers/clk/mmp/clk-mmp2.c
+++ b/drivers/clk/mmp/clk-mmp2.c
@@ -248,7 +248,8 @@ void __init mmp2_clk_init(void)
clk_register_clkdev(clk, NULL, "mmp2-pwm.3");
clk = clk_register_mux(NULL, "uart0_mux", uart_parent,
- ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(uart_parent),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
apbc_base + APBC_UART0, 4, 3, 0, &clk_lock);
clk_set_parent(clk, vctcxo);
clk_register_clkdev(clk, "uart_mux.0", NULL);
@@ -258,7 +259,8 @@ void __init mmp2_clk_init(void)
clk_register_clkdev(clk, NULL, "pxa2xx-uart.0");
clk = clk_register_mux(NULL, "uart1_mux", uart_parent,
- ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(uart_parent),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
apbc_base + APBC_UART1, 4, 3, 0, &clk_lock);
clk_set_parent(clk, vctcxo);
clk_register_clkdev(clk, "uart_mux.1", NULL);
@@ -268,7 +270,8 @@ void __init mmp2_clk_init(void)
clk_register_clkdev(clk, NULL, "pxa2xx-uart.1");
clk = clk_register_mux(NULL, "uart2_mux", uart_parent,
- ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(uart_parent),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
apbc_base + APBC_UART2, 4, 3, 0, &clk_lock);
clk_set_parent(clk, vctcxo);
clk_register_clkdev(clk, "uart_mux.2", NULL);
@@ -278,7 +281,8 @@ void __init mmp2_clk_init(void)
clk_register_clkdev(clk, NULL, "pxa2xx-uart.2");
clk = clk_register_mux(NULL, "uart3_mux", uart_parent,
- ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(uart_parent),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
apbc_base + APBC_UART3, 4, 3, 0, &clk_lock);
clk_set_parent(clk, vctcxo);
clk_register_clkdev(clk, "uart_mux.3", NULL);
@@ -288,7 +292,8 @@ void __init mmp2_clk_init(void)
clk_register_clkdev(clk, NULL, "pxa2xx-uart.3");
clk = clk_register_mux(NULL, "ssp0_mux", ssp_parent,
- ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(ssp_parent),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
apbc_base + APBC_SSP0, 4, 3, 0, &clk_lock);
clk_register_clkdev(clk, "uart_mux.0", NULL);
@@ -297,7 +302,8 @@ void __init mmp2_clk_init(void)
clk_register_clkdev(clk, NULL, "mmp-ssp.0");
clk = clk_register_mux(NULL, "ssp1_mux", ssp_parent,
- ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(ssp_parent),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
apbc_base + APBC_SSP1, 4, 3, 0, &clk_lock);
clk_register_clkdev(clk, "ssp_mux.1", NULL);
@@ -306,7 +312,8 @@ void __init mmp2_clk_init(void)
clk_register_clkdev(clk, NULL, "mmp-ssp.1");
clk = clk_register_mux(NULL, "ssp2_mux", ssp_parent,
- ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(ssp_parent),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
apbc_base + APBC_SSP2, 4, 3, 0, &clk_lock);
clk_register_clkdev(clk, "ssp_mux.2", NULL);
@@ -315,7 +322,8 @@ void __init mmp2_clk_init(void)
clk_register_clkdev(clk, NULL, "mmp-ssp.2");
clk = clk_register_mux(NULL, "ssp3_mux", ssp_parent,
- ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(ssp_parent),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
apbc_base + APBC_SSP3, 4, 3, 0, &clk_lock);
clk_register_clkdev(clk, "ssp_mux.3", NULL);
@@ -324,7 +332,8 @@ void __init mmp2_clk_init(void)
clk_register_clkdev(clk, NULL, "mmp-ssp.3");
clk = clk_register_mux(NULL, "sdh_mux", sdh_parent,
- ARRAY_SIZE(sdh_parent), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(sdh_parent),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
apmu_base + APMU_SDH0, 8, 2, 0, &clk_lock);
clk_register_clkdev(clk, "sdh_mux", NULL);
@@ -354,7 +363,8 @@ void __init mmp2_clk_init(void)
clk_register_clkdev(clk, "usb_clk", NULL);
clk = clk_register_mux(NULL, "disp0_mux", disp_parent,
- ARRAY_SIZE(disp_parent), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(disp_parent),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
apmu_base + APMU_DISP0, 6, 2, 0, &clk_lock);
clk_register_clkdev(clk, "disp_mux.0", NULL);
@@ -376,7 +386,8 @@ void __init mmp2_clk_init(void)
clk_register_clkdev(clk, "disp_sphy.0", NULL);
clk = clk_register_mux(NULL, "disp1_mux", disp_parent,
- ARRAY_SIZE(disp_parent), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(disp_parent),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
apmu_base + APMU_DISP1, 6, 2, 0, &clk_lock);
clk_register_clkdev(clk, "disp_mux.1", NULL);
@@ -394,7 +405,8 @@ void __init mmp2_clk_init(void)
clk_register_clkdev(clk, "ccic_arbiter", NULL);
clk = clk_register_mux(NULL, "ccic0_mux", ccic_parent,
- ARRAY_SIZE(ccic_parent), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(ccic_parent),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
apmu_base + APMU_CCIC0, 6, 2, 0, &clk_lock);
clk_register_clkdev(clk, "ccic_mux.0", NULL);
@@ -421,7 +433,8 @@ void __init mmp2_clk_init(void)
clk_register_clkdev(clk, "sphyclk", "mmp-ccic.0");
clk = clk_register_mux(NULL, "ccic1_mux", ccic_parent,
- ARRAY_SIZE(ccic_parent), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(ccic_parent),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
apmu_base + APMU_CCIC1, 6, 2, 0, &clk_lock);
clk_register_clkdev(clk, "ccic_mux.1", NULL);
diff --git a/drivers/clk/mmp/clk-pxa168.c b/drivers/clk/mmp/clk-pxa168.c
index 28b3b51c794b..014396b028a2 100644
--- a/drivers/clk/mmp/clk-pxa168.c
+++ b/drivers/clk/mmp/clk-pxa168.c
@@ -199,7 +199,8 @@ void __init pxa168_clk_init(void)
clk_register_clkdev(clk, NULL, "pxa168-pwm.3");
clk = clk_register_mux(NULL, "uart0_mux", uart_parent,
- ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(uart_parent),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
apbc_base + APBC_UART0, 4, 3, 0, &clk_lock);
clk_set_parent(clk, uart_pll);
clk_register_clkdev(clk, "uart_mux.0", NULL);
@@ -209,7 +210,8 @@ void __init pxa168_clk_init(void)
clk_register_clkdev(clk, NULL, "pxa2xx-uart.0");
clk = clk_register_mux(NULL, "uart1_mux", uart_parent,
- ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(uart_parent),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
apbc_base + APBC_UART1, 4, 3, 0, &clk_lock);
clk_set_parent(clk, uart_pll);
clk_register_clkdev(clk, "uart_mux.1", NULL);
@@ -219,7 +221,8 @@ void __init pxa168_clk_init(void)
clk_register_clkdev(clk, NULL, "pxa2xx-uart.1");
clk = clk_register_mux(NULL, "uart2_mux", uart_parent,
- ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(uart_parent),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
apbc_base + APBC_UART2, 4, 3, 0, &clk_lock);
clk_set_parent(clk, uart_pll);
clk_register_clkdev(clk, "uart_mux.2", NULL);
@@ -229,7 +232,8 @@ void __init pxa168_clk_init(void)
clk_register_clkdev(clk, NULL, "pxa2xx-uart.2");
clk = clk_register_mux(NULL, "ssp0_mux", ssp_parent,
- ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(ssp_parent),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
apbc_base + APBC_SSP0, 4, 3, 0, &clk_lock);
clk_register_clkdev(clk, "uart_mux.0", NULL);
@@ -238,7 +242,8 @@ void __init pxa168_clk_init(void)
clk_register_clkdev(clk, NULL, "mmp-ssp.0");
clk = clk_register_mux(NULL, "ssp1_mux", ssp_parent,
- ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(ssp_parent),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
apbc_base + APBC_SSP1, 4, 3, 0, &clk_lock);
clk_register_clkdev(clk, "ssp_mux.1", NULL);
@@ -247,7 +252,8 @@ void __init pxa168_clk_init(void)
clk_register_clkdev(clk, NULL, "mmp-ssp.1");
clk = clk_register_mux(NULL, "ssp2_mux", ssp_parent,
- ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(ssp_parent),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
apbc_base + APBC_SSP2, 4, 3, 0, &clk_lock);
clk_register_clkdev(clk, "ssp_mux.2", NULL);
@@ -256,7 +262,8 @@ void __init pxa168_clk_init(void)
clk_register_clkdev(clk, NULL, "mmp-ssp.2");
clk = clk_register_mux(NULL, "ssp3_mux", ssp_parent,
- ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(ssp_parent),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
apbc_base + APBC_SSP3, 4, 3, 0, &clk_lock);
clk_register_clkdev(clk, "ssp_mux.3", NULL);
@@ -265,7 +272,8 @@ void __init pxa168_clk_init(void)
clk_register_clkdev(clk, NULL, "mmp-ssp.3");
clk = clk_register_mux(NULL, "ssp4_mux", ssp_parent,
- ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(ssp_parent),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
apbc_base + APBC_SSP4, 4, 3, 0, &clk_lock);
clk_register_clkdev(clk, "ssp_mux.4", NULL);
@@ -278,7 +286,8 @@ void __init pxa168_clk_init(void)
clk_register_clkdev(clk, NULL, "pxa3xx-nand.0");
clk = clk_register_mux(NULL, "sdh0_mux", sdh_parent,
- ARRAY_SIZE(sdh_parent), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(sdh_parent),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
apmu_base + APMU_SDH0, 6, 1, 0, &clk_lock);
clk_register_clkdev(clk, "sdh0_mux", NULL);
@@ -287,7 +296,8 @@ void __init pxa168_clk_init(void)
clk_register_clkdev(clk, NULL, "sdhci-pxa.0");
clk = clk_register_mux(NULL, "sdh1_mux", sdh_parent,
- ARRAY_SIZE(sdh_parent), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(sdh_parent),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
apmu_base + APMU_SDH1, 6, 1, 0, &clk_lock);
clk_register_clkdev(clk, "sdh1_mux", NULL);
@@ -304,7 +314,8 @@ void __init pxa168_clk_init(void)
clk_register_clkdev(clk, "sph_clk", NULL);
clk = clk_register_mux(NULL, "disp0_mux", disp_parent,
- ARRAY_SIZE(disp_parent), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(disp_parent),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
apmu_base + APMU_DISP0, 6, 1, 0, &clk_lock);
clk_register_clkdev(clk, "disp_mux.0", NULL);
@@ -317,7 +328,8 @@ void __init pxa168_clk_init(void)
clk_register_clkdev(clk, "hclk", "mmp-disp.0");
clk = clk_register_mux(NULL, "ccic0_mux", ccic_parent,
- ARRAY_SIZE(ccic_parent), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(ccic_parent),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
apmu_base + APMU_CCIC0, 6, 1, 0, &clk_lock);
clk_register_clkdev(clk, "ccic_mux.0", NULL);
@@ -327,8 +339,8 @@ void __init pxa168_clk_init(void)
clk = clk_register_mux(NULL, "ccic0_phy_mux", ccic_phy_parent,
ARRAY_SIZE(ccic_phy_parent),
- CLK_SET_RATE_PARENT, apmu_base + APMU_CCIC0,
- 7, 1, 0, &clk_lock);
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
+ apmu_base + APMU_CCIC0, 7, 1, 0, &clk_lock);
clk_register_clkdev(clk, "ccic_phy_mux.0", NULL);
clk = mmp_clk_register_apmu("ccic0_phy", "ccic0_phy_mux",
diff --git a/drivers/clk/mmp/clk-pxa910.c b/drivers/clk/mmp/clk-pxa910.c
index 6ec05698ed38..9efc6a47535d 100644
--- a/drivers/clk/mmp/clk-pxa910.c
+++ b/drivers/clk/mmp/clk-pxa910.c
@@ -204,7 +204,8 @@ void __init pxa910_clk_init(void)
clk_register_clkdev(clk, NULL, "pxa910-pwm.3");
clk = clk_register_mux(NULL, "uart0_mux", uart_parent,
- ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(uart_parent),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
apbc_base + APBC_UART0, 4, 3, 0, &clk_lock);
clk_set_parent(clk, uart_pll);
clk_register_clkdev(clk, "uart_mux.0", NULL);
@@ -214,7 +215,8 @@ void __init pxa910_clk_init(void)
clk_register_clkdev(clk, NULL, "pxa2xx-uart.0");
clk = clk_register_mux(NULL, "uart1_mux", uart_parent,
- ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(uart_parent),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
apbc_base + APBC_UART1, 4, 3, 0, &clk_lock);
clk_set_parent(clk, uart_pll);
clk_register_clkdev(clk, "uart_mux.1", NULL);
@@ -224,7 +226,8 @@ void __init pxa910_clk_init(void)
clk_register_clkdev(clk, NULL, "pxa2xx-uart.1");
clk = clk_register_mux(NULL, "uart2_mux", uart_parent,
- ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(uart_parent),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
apbcp_base + APBCP_UART2, 4, 3, 0, &clk_lock);
clk_set_parent(clk, uart_pll);
clk_register_clkdev(clk, "uart_mux.2", NULL);
@@ -234,7 +237,8 @@ void __init pxa910_clk_init(void)
clk_register_clkdev(clk, NULL, "pxa2xx-uart.2");
clk = clk_register_mux(NULL, "ssp0_mux", ssp_parent,
- ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(ssp_parent),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
apbc_base + APBC_SSP0, 4, 3, 0, &clk_lock);
clk_register_clkdev(clk, "uart_mux.0", NULL);
@@ -243,7 +247,8 @@ void __init pxa910_clk_init(void)
clk_register_clkdev(clk, NULL, "mmp-ssp.0");
clk = clk_register_mux(NULL, "ssp1_mux", ssp_parent,
- ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(ssp_parent),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
apbc_base + APBC_SSP1, 4, 3, 0, &clk_lock);
clk_register_clkdev(clk, "ssp_mux.1", NULL);
@@ -256,7 +261,8 @@ void __init pxa910_clk_init(void)
clk_register_clkdev(clk, NULL, "pxa3xx-nand.0");
clk = clk_register_mux(NULL, "sdh0_mux", sdh_parent,
- ARRAY_SIZE(sdh_parent), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(sdh_parent),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
apmu_base + APMU_SDH0, 6, 1, 0, &clk_lock);
clk_register_clkdev(clk, "sdh0_mux", NULL);
@@ -265,7 +271,8 @@ void __init pxa910_clk_init(void)
clk_register_clkdev(clk, NULL, "sdhci-pxa.0");
clk = clk_register_mux(NULL, "sdh1_mux", sdh_parent,
- ARRAY_SIZE(sdh_parent), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(sdh_parent),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
apmu_base + APMU_SDH1, 6, 1, 0, &clk_lock);
clk_register_clkdev(clk, "sdh1_mux", NULL);
@@ -282,7 +289,8 @@ void __init pxa910_clk_init(void)
clk_register_clkdev(clk, "sph_clk", NULL);
clk = clk_register_mux(NULL, "disp0_mux", disp_parent,
- ARRAY_SIZE(disp_parent), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(disp_parent),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
apmu_base + APMU_DISP0, 6, 1, 0, &clk_lock);
clk_register_clkdev(clk, "disp_mux.0", NULL);
@@ -291,7 +299,8 @@ void __init pxa910_clk_init(void)
clk_register_clkdev(clk, NULL, "mmp-disp.0");
clk = clk_register_mux(NULL, "ccic0_mux", ccic_parent,
- ARRAY_SIZE(ccic_parent), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(ccic_parent),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
apmu_base + APMU_CCIC0, 6, 1, 0, &clk_lock);
clk_register_clkdev(clk, "ccic_mux.0", NULL);
@@ -301,8 +310,8 @@ void __init pxa910_clk_init(void)
clk = clk_register_mux(NULL, "ccic0_phy_mux", ccic_phy_parent,
ARRAY_SIZE(ccic_phy_parent),
- CLK_SET_RATE_PARENT, apmu_base + APMU_CCIC0,
- 7, 1, 0, &clk_lock);
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
+ apmu_base + APMU_CCIC0, 7, 1, 0, &clk_lock);
clk_register_clkdev(clk, "ccic_phy_mux.0", NULL);
clk = mmp_clk_register_apmu("ccic0_phy", "ccic0_phy_mux",
diff --git a/drivers/clk/mxs/clk.h b/drivers/clk/mxs/clk.h
index 81421e28e69c..ef10ad9b5daa 100644
--- a/drivers/clk/mxs/clk.h
+++ b/drivers/clk/mxs/clk.h
@@ -52,8 +52,8 @@ static inline struct clk *mxs_clk_mux(const char *name, void __iomem *reg,
u8 shift, u8 width, const char **parent_names, int num_parents)
{
return clk_register_mux(NULL, name, parent_names, num_parents,
- CLK_SET_RATE_PARENT, reg, shift, width,
- 0, &mxs_lock);
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
+ reg, shift, width, 0, &mxs_lock);
}
static inline struct clk *mxs_clk_fixed_factor(const char *name,
diff --git a/drivers/clk/spear/spear1310_clock.c b/drivers/clk/spear/spear1310_clock.c
index aedbbe12f321..65894f7687ed 100644
--- a/drivers/clk/spear/spear1310_clock.c
+++ b/drivers/clk/spear/spear1310_clock.c
@@ -416,9 +416,9 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
/* clock derived from 24 or 25 MHz osc clk */
/* vco-pll */
clk = clk_register_mux(NULL, "vco1_mclk", vco_parents,
- ARRAY_SIZE(vco_parents), 0, SPEAR1310_PLL_CFG,
- SPEAR1310_PLL1_CLK_SHIFT, SPEAR1310_PLL_CLK_MASK, 0,
- &_lock);
+ ARRAY_SIZE(vco_parents), CLK_SET_RATE_NO_REPARENT,
+ SPEAR1310_PLL_CFG, SPEAR1310_PLL1_CLK_SHIFT,
+ SPEAR1310_PLL_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "vco1_mclk", NULL);
clk = clk_register_vco_pll("vco1_clk", "pll1_clk", NULL, "vco1_mclk",
0, SPEAR1310_PLL1_CTR, SPEAR1310_PLL1_FRQ, pll_rtbl,
@@ -427,9 +427,9 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
clk_register_clkdev(clk1, "pll1_clk", NULL);
clk = clk_register_mux(NULL, "vco2_mclk", vco_parents,
- ARRAY_SIZE(vco_parents), 0, SPEAR1310_PLL_CFG,
- SPEAR1310_PLL2_CLK_SHIFT, SPEAR1310_PLL_CLK_MASK, 0,
- &_lock);
+ ARRAY_SIZE(vco_parents), CLK_SET_RATE_NO_REPARENT,
+ SPEAR1310_PLL_CFG, SPEAR1310_PLL2_CLK_SHIFT,
+ SPEAR1310_PLL_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "vco2_mclk", NULL);
clk = clk_register_vco_pll("vco2_clk", "pll2_clk", NULL, "vco2_mclk",
0, SPEAR1310_PLL2_CTR, SPEAR1310_PLL2_FRQ, pll_rtbl,
@@ -438,9 +438,9 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
clk_register_clkdev(clk1, "pll2_clk", NULL);
clk = clk_register_mux(NULL, "vco3_mclk", vco_parents,
- ARRAY_SIZE(vco_parents), 0, SPEAR1310_PLL_CFG,
- SPEAR1310_PLL3_CLK_SHIFT, SPEAR1310_PLL_CLK_MASK, 0,
- &_lock);
+ ARRAY_SIZE(vco_parents), CLK_SET_RATE_NO_REPARENT,
+ SPEAR1310_PLL_CFG, SPEAR1310_PLL3_CLK_SHIFT,
+ SPEAR1310_PLL_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "vco3_mclk", NULL);
clk = clk_register_vco_pll("vco3_clk", "pll3_clk", NULL, "vco3_mclk",
0, SPEAR1310_PLL3_CTR, SPEAR1310_PLL3_FRQ, pll_rtbl,
@@ -515,9 +515,9 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
/* gpt clocks */
clk = clk_register_mux(NULL, "gpt0_mclk", gpt_parents,
- ARRAY_SIZE(gpt_parents), 0, SPEAR1310_PERIP_CLK_CFG,
- SPEAR1310_GPT0_CLK_SHIFT, SPEAR1310_GPT_CLK_MASK, 0,
- &_lock);
+ ARRAY_SIZE(gpt_parents), CLK_SET_RATE_NO_REPARENT,
+ SPEAR1310_PERIP_CLK_CFG, SPEAR1310_GPT0_CLK_SHIFT,
+ SPEAR1310_GPT_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "gpt0_mclk", NULL);
clk = clk_register_gate(NULL, "gpt0_clk", "gpt0_mclk", 0,
SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_GPT0_CLK_ENB, 0,
@@ -525,9 +525,9 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
clk_register_clkdev(clk, NULL, "gpt0");
clk = clk_register_mux(NULL, "gpt1_mclk", gpt_parents,
- ARRAY_SIZE(gpt_parents), 0, SPEAR1310_PERIP_CLK_CFG,
- SPEAR1310_GPT1_CLK_SHIFT, SPEAR1310_GPT_CLK_MASK, 0,
- &_lock);
+ ARRAY_SIZE(gpt_parents), CLK_SET_RATE_NO_REPARENT,
+ SPEAR1310_PERIP_CLK_CFG, SPEAR1310_GPT1_CLK_SHIFT,
+ SPEAR1310_GPT_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "gpt1_mclk", NULL);
clk = clk_register_gate(NULL, "gpt1_clk", "gpt1_mclk", 0,
SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_GPT1_CLK_ENB, 0,
@@ -535,9 +535,9 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
clk_register_clkdev(clk, NULL, "gpt1");
clk = clk_register_mux(NULL, "gpt2_mclk", gpt_parents,
- ARRAY_SIZE(gpt_parents), 0, SPEAR1310_PERIP_CLK_CFG,
- SPEAR1310_GPT2_CLK_SHIFT, SPEAR1310_GPT_CLK_MASK, 0,
- &_lock);
+ ARRAY_SIZE(gpt_parents), CLK_SET_RATE_NO_REPARENT,
+ SPEAR1310_PERIP_CLK_CFG, SPEAR1310_GPT2_CLK_SHIFT,
+ SPEAR1310_GPT_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "gpt2_mclk", NULL);
clk = clk_register_gate(NULL, "gpt2_clk", "gpt2_mclk", 0,
SPEAR1310_PERIP2_CLK_ENB, SPEAR1310_GPT2_CLK_ENB, 0,
@@ -545,9 +545,9 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
clk_register_clkdev(clk, NULL, "gpt2");
clk = clk_register_mux(NULL, "gpt3_mclk", gpt_parents,
- ARRAY_SIZE(gpt_parents), 0, SPEAR1310_PERIP_CLK_CFG,
- SPEAR1310_GPT3_CLK_SHIFT, SPEAR1310_GPT_CLK_MASK, 0,
- &_lock);
+ ARRAY_SIZE(gpt_parents), CLK_SET_RATE_NO_REPARENT,
+ SPEAR1310_PERIP_CLK_CFG, SPEAR1310_GPT3_CLK_SHIFT,
+ SPEAR1310_GPT_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "gpt3_mclk", NULL);
clk = clk_register_gate(NULL, "gpt3_clk", "gpt3_mclk", 0,
SPEAR1310_PERIP2_CLK_ENB, SPEAR1310_GPT3_CLK_ENB, 0,
@@ -562,7 +562,8 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
clk_register_clkdev(clk1, "uart_syn_gclk", NULL);
clk = clk_register_mux(NULL, "uart0_mclk", uart0_parents,
- ARRAY_SIZE(uart0_parents), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(uart0_parents),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
SPEAR1310_PERIP_CLK_CFG, SPEAR1310_UART_CLK_SHIFT,
SPEAR1310_UART_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "uart0_mclk", NULL);
@@ -602,7 +603,8 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
clk_register_clkdev(clk1, "c3_syn_gclk", NULL);
clk = clk_register_mux(NULL, "c3_mclk", c3_parents,
- ARRAY_SIZE(c3_parents), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(c3_parents),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
SPEAR1310_PERIP_CLK_CFG, SPEAR1310_C3_CLK_SHIFT,
SPEAR1310_C3_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "c3_mclk", NULL);
@@ -614,8 +616,8 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
/* gmac */
clk = clk_register_mux(NULL, "phy_input_mclk", gmac_phy_input_parents,
- ARRAY_SIZE(gmac_phy_input_parents), 0,
- SPEAR1310_GMAC_CLK_CFG,
+ ARRAY_SIZE(gmac_phy_input_parents),
+ CLK_SET_RATE_NO_REPARENT, SPEAR1310_GMAC_CLK_CFG,
SPEAR1310_GMAC_PHY_INPUT_CLK_SHIFT,
SPEAR1310_GMAC_PHY_INPUT_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "phy_input_mclk", NULL);
@@ -627,15 +629,16 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
clk_register_clkdev(clk1, "phy_syn_gclk", NULL);
clk = clk_register_mux(NULL, "phy_mclk", gmac_phy_parents,
- ARRAY_SIZE(gmac_phy_parents), 0,
+ ARRAY_SIZE(gmac_phy_parents), CLK_SET_RATE_NO_REPARENT,
SPEAR1310_PERIP_CLK_CFG, SPEAR1310_GMAC_PHY_CLK_SHIFT,
SPEAR1310_GMAC_PHY_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "stmmacphy.0", NULL);
/* clcd */
clk = clk_register_mux(NULL, "clcd_syn_mclk", clcd_synth_parents,
- ARRAY_SIZE(clcd_synth_parents), 0,
- SPEAR1310_CLCD_CLK_SYNT, SPEAR1310_CLCD_SYNT_CLK_SHIFT,
+ ARRAY_SIZE(clcd_synth_parents),
+ CLK_SET_RATE_NO_REPARENT, SPEAR1310_CLCD_CLK_SYNT,
+ SPEAR1310_CLCD_SYNT_CLK_SHIFT,
SPEAR1310_CLCD_SYNT_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "clcd_syn_mclk", NULL);
@@ -645,7 +648,8 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
clk_register_clkdev(clk, "clcd_syn_clk", NULL);
clk = clk_register_mux(NULL, "clcd_pixel_mclk", clcd_pixel_parents,
- ARRAY_SIZE(clcd_pixel_parents), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(clcd_pixel_parents),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
SPEAR1310_PERIP_CLK_CFG, SPEAR1310_CLCD_CLK_SHIFT,
SPEAR1310_CLCD_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "clcd_pixel_mclk", NULL);
@@ -657,9 +661,9 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
/* i2s */
clk = clk_register_mux(NULL, "i2s_src_mclk", i2s_src_parents,
- ARRAY_SIZE(i2s_src_parents), 0, SPEAR1310_I2S_CLK_CFG,
- SPEAR1310_I2S_SRC_CLK_SHIFT, SPEAR1310_I2S_SRC_CLK_MASK,
- 0, &_lock);
+ ARRAY_SIZE(i2s_src_parents), CLK_SET_RATE_NO_REPARENT,
+ SPEAR1310_I2S_CLK_CFG, SPEAR1310_I2S_SRC_CLK_SHIFT,
+ SPEAR1310_I2S_SRC_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "i2s_src_mclk", NULL);
clk = clk_register_aux("i2s_prs1_clk", NULL, "i2s_src_mclk", 0,
@@ -668,7 +672,8 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
clk_register_clkdev(clk, "i2s_prs1_clk", NULL);
clk = clk_register_mux(NULL, "i2s_ref_mclk", i2s_ref_parents,
- ARRAY_SIZE(i2s_ref_parents), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(i2s_ref_parents),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
SPEAR1310_I2S_CLK_CFG, SPEAR1310_I2S_REF_SHIFT,
SPEAR1310_I2S_REF_SEL_MASK, 0, &_lock);
clk_register_clkdev(clk, "i2s_ref_mclk", NULL);
@@ -806,13 +811,15 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
/* RAS clks */
clk = clk_register_mux(NULL, "gen_syn0_1_mclk", gen_synth0_1_parents,
- ARRAY_SIZE(gen_synth0_1_parents), 0, SPEAR1310_PLL_CFG,
+ ARRAY_SIZE(gen_synth0_1_parents),
+ CLK_SET_RATE_NO_REPARENT, SPEAR1310_PLL_CFG,
SPEAR1310_RAS_SYNT0_1_CLK_SHIFT,
SPEAR1310_RAS_SYNT_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "gen_syn0_1_clk", NULL);
clk = clk_register_mux(NULL, "gen_syn2_3_mclk", gen_synth2_3_parents,
- ARRAY_SIZE(gen_synth2_3_parents), 0, SPEAR1310_PLL_CFG,
+ ARRAY_SIZE(gen_synth2_3_parents),
+ CLK_SET_RATE_NO_REPARENT, SPEAR1310_PLL_CFG,
SPEAR1310_RAS_SYNT2_3_CLK_SHIFT,
SPEAR1310_RAS_SYNT_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "gen_syn2_3_clk", NULL);
@@ -929,8 +936,8 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
clk = clk_register_mux(NULL, "smii_rgmii_phy_mclk",
smii_rgmii_phy_parents,
- ARRAY_SIZE(smii_rgmii_phy_parents), 0,
- SPEAR1310_RAS_CTRL_REG1,
+ ARRAY_SIZE(smii_rgmii_phy_parents),
+ CLK_SET_RATE_NO_REPARENT, SPEAR1310_RAS_CTRL_REG1,
SPEAR1310_SMII_RGMII_PHY_CLK_SHIFT,
SPEAR1310_PHY_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "stmmacphy.1", NULL);
@@ -938,15 +945,15 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
clk_register_clkdev(clk, "stmmacphy.4", NULL);
clk = clk_register_mux(NULL, "rmii_phy_mclk", rmii_phy_parents,
- ARRAY_SIZE(rmii_phy_parents), 0,
+ ARRAY_SIZE(rmii_phy_parents), CLK_SET_RATE_NO_REPARENT,
SPEAR1310_RAS_CTRL_REG1, SPEAR1310_RMII_PHY_CLK_SHIFT,
SPEAR1310_PHY_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "stmmacphy.3", NULL);
clk = clk_register_mux(NULL, "uart1_mclk", uart_parents,
- ARRAY_SIZE(uart_parents), 0, SPEAR1310_RAS_CTRL_REG0,
- SPEAR1310_UART1_CLK_SHIFT, SPEAR1310_RAS_UART_CLK_MASK,
- 0, &_lock);
+ ARRAY_SIZE(uart_parents), CLK_SET_RATE_NO_REPARENT,
+ SPEAR1310_RAS_CTRL_REG0, SPEAR1310_UART1_CLK_SHIFT,
+ SPEAR1310_RAS_UART_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "uart1_mclk", NULL);
clk = clk_register_gate(NULL, "uart1_clk", "uart1_mclk", 0,
@@ -955,9 +962,9 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
clk_register_clkdev(clk, NULL, "5c800000.serial");
clk = clk_register_mux(NULL, "uart2_mclk", uart_parents,
- ARRAY_SIZE(uart_parents), 0, SPEAR1310_RAS_CTRL_REG0,
- SPEAR1310_UART2_CLK_SHIFT, SPEAR1310_RAS_UART_CLK_MASK,
- 0, &_lock);
+ ARRAY_SIZE(uart_parents), CLK_SET_RATE_NO_REPARENT,
+ SPEAR1310_RAS_CTRL_REG0, SPEAR1310_UART2_CLK_SHIFT,
+ SPEAR1310_RAS_UART_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "uart2_mclk", NULL);
clk = clk_register_gate(NULL, "uart2_clk", "uart2_mclk", 0,
@@ -966,9 +973,9 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
clk_register_clkdev(clk, NULL, "5c900000.serial");
clk = clk_register_mux(NULL, "uart3_mclk", uart_parents,
- ARRAY_SIZE(uart_parents), 0, SPEAR1310_RAS_CTRL_REG0,
- SPEAR1310_UART3_CLK_SHIFT, SPEAR1310_RAS_UART_CLK_MASK,
- 0, &_lock);
+ ARRAY_SIZE(uart_parents), CLK_SET_RATE_NO_REPARENT,
+ SPEAR1310_RAS_CTRL_REG0, SPEAR1310_UART3_CLK_SHIFT,
+ SPEAR1310_RAS_UART_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "uart3_mclk", NULL);
clk = clk_register_gate(NULL, "uart3_clk", "uart3_mclk", 0,
@@ -977,9 +984,9 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
clk_register_clkdev(clk, NULL, "5ca00000.serial");
clk = clk_register_mux(NULL, "uart4_mclk", uart_parents,
- ARRAY_SIZE(uart_parents), 0, SPEAR1310_RAS_CTRL_REG0,
- SPEAR1310_UART4_CLK_SHIFT, SPEAR1310_RAS_UART_CLK_MASK,
- 0, &_lock);
+ ARRAY_SIZE(uart_parents), CLK_SET_RATE_NO_REPARENT,
+ SPEAR1310_RAS_CTRL_REG0, SPEAR1310_UART4_CLK_SHIFT,
+ SPEAR1310_RAS_UART_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "uart4_mclk", NULL);
clk = clk_register_gate(NULL, "uart4_clk", "uart4_mclk", 0,
@@ -988,9 +995,9 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
clk_register_clkdev(clk, NULL, "5cb00000.serial");
clk = clk_register_mux(NULL, "uart5_mclk", uart_parents,
- ARRAY_SIZE(uart_parents), 0, SPEAR1310_RAS_CTRL_REG0,
- SPEAR1310_UART5_CLK_SHIFT, SPEAR1310_RAS_UART_CLK_MASK,
- 0, &_lock);
+ ARRAY_SIZE(uart_parents), CLK_SET_RATE_NO_REPARENT,
+ SPEAR1310_RAS_CTRL_REG0, SPEAR1310_UART5_CLK_SHIFT,
+ SPEAR1310_RAS_UART_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "uart5_mclk", NULL);
clk = clk_register_gate(NULL, "uart5_clk", "uart5_mclk", 0,
@@ -999,9 +1006,9 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
clk_register_clkdev(clk, NULL, "5cc00000.serial");
clk = clk_register_mux(NULL, "i2c1_mclk", i2c_parents,
- ARRAY_SIZE(i2c_parents), 0, SPEAR1310_RAS_CTRL_REG0,
- SPEAR1310_I2C1_CLK_SHIFT, SPEAR1310_I2C_CLK_MASK, 0,
- &_lock);
+ ARRAY_SIZE(i2c_parents), CLK_SET_RATE_NO_REPARENT,
+ SPEAR1310_RAS_CTRL_REG0, SPEAR1310_I2C1_CLK_SHIFT,
+ SPEAR1310_I2C_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "i2c1_mclk", NULL);
clk = clk_register_gate(NULL, "i2c1_clk", "i2c1_mclk", 0,
@@ -1010,9 +1017,9 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
clk_register_clkdev(clk, NULL, "5cd00000.i2c");
clk = clk_register_mux(NULL, "i2c2_mclk", i2c_parents,
- ARRAY_SIZE(i2c_parents), 0, SPEAR1310_RAS_CTRL_REG0,
- SPEAR1310_I2C2_CLK_SHIFT, SPEAR1310_I2C_CLK_MASK, 0,
- &_lock);
+ ARRAY_SIZE(i2c_parents), CLK_SET_RATE_NO_REPARENT,
+ SPEAR1310_RAS_CTRL_REG0, SPEAR1310_I2C2_CLK_SHIFT,
+ SPEAR1310_I2C_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "i2c2_mclk", NULL);
clk = clk_register_gate(NULL, "i2c2_clk", "i2c2_mclk", 0,
@@ -1021,9 +1028,9 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
clk_register_clkdev(clk, NULL, "5ce00000.i2c");
clk = clk_register_mux(NULL, "i2c3_mclk", i2c_parents,
- ARRAY_SIZE(i2c_parents), 0, SPEAR1310_RAS_CTRL_REG0,
- SPEAR1310_I2C3_CLK_SHIFT, SPEAR1310_I2C_CLK_MASK, 0,
- &_lock);
+ ARRAY_SIZE(i2c_parents), CLK_SET_RATE_NO_REPARENT,
+ SPEAR1310_RAS_CTRL_REG0, SPEAR1310_I2C3_CLK_SHIFT,
+ SPEAR1310_I2C_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "i2c3_mclk", NULL);
clk = clk_register_gate(NULL, "i2c3_clk", "i2c3_mclk", 0,
@@ -1032,9 +1039,9 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
clk_register_clkdev(clk, NULL, "5cf00000.i2c");
clk = clk_register_mux(NULL, "i2c4_mclk", i2c_parents,
- ARRAY_SIZE(i2c_parents), 0, SPEAR1310_RAS_CTRL_REG0,
- SPEAR1310_I2C4_CLK_SHIFT, SPEAR1310_I2C_CLK_MASK, 0,
- &_lock);
+ ARRAY_SIZE(i2c_parents), CLK_SET_RATE_NO_REPARENT,
+ SPEAR1310_RAS_CTRL_REG0, SPEAR1310_I2C4_CLK_SHIFT,
+ SPEAR1310_I2C_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "i2c4_mclk", NULL);
clk = clk_register_gate(NULL, "i2c4_clk", "i2c4_mclk", 0,
@@ -1043,9 +1050,9 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
clk_register_clkdev(clk, NULL, "5d000000.i2c");
clk = clk_register_mux(NULL, "i2c5_mclk", i2c_parents,
- ARRAY_SIZE(i2c_parents), 0, SPEAR1310_RAS_CTRL_REG0,
- SPEAR1310_I2C5_CLK_SHIFT, SPEAR1310_I2C_CLK_MASK, 0,
- &_lock);
+ ARRAY_SIZE(i2c_parents), CLK_SET_RATE_NO_REPARENT,
+ SPEAR1310_RAS_CTRL_REG0, SPEAR1310_I2C5_CLK_SHIFT,
+ SPEAR1310_I2C_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "i2c5_mclk", NULL);
clk = clk_register_gate(NULL, "i2c5_clk", "i2c5_mclk", 0,
@@ -1054,9 +1061,9 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
clk_register_clkdev(clk, NULL, "5d100000.i2c");
clk = clk_register_mux(NULL, "i2c6_mclk", i2c_parents,
- ARRAY_SIZE(i2c_parents), 0, SPEAR1310_RAS_CTRL_REG0,
- SPEAR1310_I2C6_CLK_SHIFT, SPEAR1310_I2C_CLK_MASK, 0,
- &_lock);
+ ARRAY_SIZE(i2c_parents), CLK_SET_RATE_NO_REPARENT,
+ SPEAR1310_RAS_CTRL_REG0, SPEAR1310_I2C6_CLK_SHIFT,
+ SPEAR1310_I2C_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "i2c6_mclk", NULL);
clk = clk_register_gate(NULL, "i2c6_clk", "i2c6_mclk", 0,
@@ -1065,9 +1072,9 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
clk_register_clkdev(clk, NULL, "5d200000.i2c");
clk = clk_register_mux(NULL, "i2c7_mclk", i2c_parents,
- ARRAY_SIZE(i2c_parents), 0, SPEAR1310_RAS_CTRL_REG0,
- SPEAR1310_I2C7_CLK_SHIFT, SPEAR1310_I2C_CLK_MASK, 0,
- &_lock);
+ ARRAY_SIZE(i2c_parents), CLK_SET_RATE_NO_REPARENT,
+ SPEAR1310_RAS_CTRL_REG0, SPEAR1310_I2C7_CLK_SHIFT,
+ SPEAR1310_I2C_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "i2c7_mclk", NULL);
clk = clk_register_gate(NULL, "i2c7_clk", "i2c7_mclk", 0,
@@ -1076,9 +1083,9 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
clk_register_clkdev(clk, NULL, "5d300000.i2c");
clk = clk_register_mux(NULL, "ssp1_mclk", ssp1_parents,
- ARRAY_SIZE(ssp1_parents), 0, SPEAR1310_RAS_CTRL_REG0,
- SPEAR1310_SSP1_CLK_SHIFT, SPEAR1310_SSP1_CLK_MASK, 0,
- &_lock);
+ ARRAY_SIZE(ssp1_parents), CLK_SET_RATE_NO_REPARENT,
+ SPEAR1310_RAS_CTRL_REG0, SPEAR1310_SSP1_CLK_SHIFT,
+ SPEAR1310_SSP1_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "ssp1_mclk", NULL);
clk = clk_register_gate(NULL, "ssp1_clk", "ssp1_mclk", 0,
@@ -1087,9 +1094,9 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
clk_register_clkdev(clk, NULL, "5d400000.spi");
clk = clk_register_mux(NULL, "pci_mclk", pci_parents,
- ARRAY_SIZE(pci_parents), 0, SPEAR1310_RAS_CTRL_REG0,
- SPEAR1310_PCI_CLK_SHIFT, SPEAR1310_PCI_CLK_MASK, 0,
- &_lock);
+ ARRAY_SIZE(pci_parents), CLK_SET_RATE_NO_REPARENT,
+ SPEAR1310_RAS_CTRL_REG0, SPEAR1310_PCI_CLK_SHIFT,
+ SPEAR1310_PCI_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "pci_mclk", NULL);
clk = clk_register_gate(NULL, "pci_clk", "pci_mclk", 0,
@@ -1098,9 +1105,9 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
clk_register_clkdev(clk, NULL, "pci");
clk = clk_register_mux(NULL, "tdm1_mclk", tdm_parents,
- ARRAY_SIZE(tdm_parents), 0, SPEAR1310_RAS_CTRL_REG0,
- SPEAR1310_TDM1_CLK_SHIFT, SPEAR1310_TDM_CLK_MASK, 0,
- &_lock);
+ ARRAY_SIZE(tdm_parents), CLK_SET_RATE_NO_REPARENT,
+ SPEAR1310_RAS_CTRL_REG0, SPEAR1310_TDM1_CLK_SHIFT,
+ SPEAR1310_TDM_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "tdm1_mclk", NULL);
clk = clk_register_gate(NULL, "tdm1_clk", "tdm1_mclk", 0,
@@ -1109,9 +1116,9 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
clk_register_clkdev(clk, NULL, "tdm_hdlc.0");
clk = clk_register_mux(NULL, "tdm2_mclk", tdm_parents,
- ARRAY_SIZE(tdm_parents), 0, SPEAR1310_RAS_CTRL_REG0,
- SPEAR1310_TDM2_CLK_SHIFT, SPEAR1310_TDM_CLK_MASK, 0,
- &_lock);
+ ARRAY_SIZE(tdm_parents), CLK_SET_RATE_NO_REPARENT,
+ SPEAR1310_RAS_CTRL_REG0, SPEAR1310_TDM2_CLK_SHIFT,
+ SPEAR1310_TDM_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "tdm2_mclk", NULL);
clk = clk_register_gate(NULL, "tdm2_clk", "tdm2_mclk", 0,
diff --git a/drivers/clk/spear/spear1340_clock.c b/drivers/clk/spear/spear1340_clock.c
index 9d0b3949db30..fe835c1845fe 100644
--- a/drivers/clk/spear/spear1340_clock.c
+++ b/drivers/clk/spear/spear1340_clock.c
@@ -473,9 +473,9 @@ void __init spear1340_clk_init(void __iomem *misc_base)
/* clock derived from 24 or 25 MHz osc clk */
/* vco-pll */
clk = clk_register_mux(NULL, "vco1_mclk", vco_parents,
- ARRAY_SIZE(vco_parents), 0, SPEAR1340_PLL_CFG,
- SPEAR1340_PLL1_CLK_SHIFT, SPEAR1340_PLL_CLK_MASK, 0,
- &_lock);
+ ARRAY_SIZE(vco_parents), CLK_SET_RATE_NO_REPARENT,
+ SPEAR1340_PLL_CFG, SPEAR1340_PLL1_CLK_SHIFT,
+ SPEAR1340_PLL_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "vco1_mclk", NULL);
clk = clk_register_vco_pll("vco1_clk", "pll1_clk", NULL, "vco1_mclk", 0,
SPEAR1340_PLL1_CTR, SPEAR1340_PLL1_FRQ, pll_rtbl,
@@ -484,9 +484,9 @@ void __init spear1340_clk_init(void __iomem *misc_base)
clk_register_clkdev(clk1, "pll1_clk", NULL);
clk = clk_register_mux(NULL, "vco2_mclk", vco_parents,
- ARRAY_SIZE(vco_parents), 0, SPEAR1340_PLL_CFG,
- SPEAR1340_PLL2_CLK_SHIFT, SPEAR1340_PLL_CLK_MASK, 0,
- &_lock);
+ ARRAY_SIZE(vco_parents), CLK_SET_RATE_NO_REPARENT,
+ SPEAR1340_PLL_CFG, SPEAR1340_PLL2_CLK_SHIFT,
+ SPEAR1340_PLL_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "vco2_mclk", NULL);
clk = clk_register_vco_pll("vco2_clk", "pll2_clk", NULL, "vco2_mclk", 0,
SPEAR1340_PLL2_CTR, SPEAR1340_PLL2_FRQ, pll_rtbl,
@@ -495,9 +495,9 @@ void __init spear1340_clk_init(void __iomem *misc_base)
clk_register_clkdev(clk1, "pll2_clk", NULL);
clk = clk_register_mux(NULL, "vco3_mclk", vco_parents,
- ARRAY_SIZE(vco_parents), 0, SPEAR1340_PLL_CFG,
- SPEAR1340_PLL3_CLK_SHIFT, SPEAR1340_PLL_CLK_MASK, 0,
- &_lock);
+ ARRAY_SIZE(vco_parents), CLK_SET_RATE_NO_REPARENT,
+ SPEAR1340_PLL_CFG, SPEAR1340_PLL3_CLK_SHIFT,
+ SPEAR1340_PLL_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "vco3_mclk", NULL);
clk = clk_register_vco_pll("vco3_clk", "pll3_clk", NULL, "vco3_mclk", 0,
SPEAR1340_PLL3_CTR, SPEAR1340_PLL3_FRQ, pll_rtbl,
@@ -561,8 +561,8 @@ void __init spear1340_clk_init(void __iomem *misc_base)
clk_register_clkdev(clk, "amba_syn_clk", NULL);
clk = clk_register_mux(NULL, "sys_mclk", sys_parents,
- ARRAY_SIZE(sys_parents), 0, SPEAR1340_SYS_CLK_CTRL,
- SPEAR1340_SCLK_SRC_SEL_SHIFT,
+ ARRAY_SIZE(sys_parents), CLK_SET_RATE_NO_REPARENT,
+ SPEAR1340_SYS_CLK_CTRL, SPEAR1340_SCLK_SRC_SEL_SHIFT,
SPEAR1340_SCLK_SRC_SEL_MASK, 0, &_lock);
clk_register_clkdev(clk, "sys_mclk", NULL);
@@ -583,8 +583,8 @@ void __init spear1340_clk_init(void __iomem *misc_base)
clk_register_clkdev(clk, NULL, "smp_twd");
clk = clk_register_mux(NULL, "ahb_clk", ahb_parents,
- ARRAY_SIZE(ahb_parents), 0, SPEAR1340_SYS_CLK_CTRL,
- SPEAR1340_HCLK_SRC_SEL_SHIFT,
+ ARRAY_SIZE(ahb_parents), CLK_SET_RATE_NO_REPARENT,
+ SPEAR1340_SYS_CLK_CTRL, SPEAR1340_HCLK_SRC_SEL_SHIFT,
SPEAR1340_HCLK_SRC_SEL_MASK, 0, &_lock);
clk_register_clkdev(clk, "ahb_clk", NULL);
@@ -594,9 +594,9 @@ void __init spear1340_clk_init(void __iomem *misc_base)
/* gpt clocks */
clk = clk_register_mux(NULL, "gpt0_mclk", gpt_parents,
- ARRAY_SIZE(gpt_parents), 0, SPEAR1340_PERIP_CLK_CFG,
- SPEAR1340_GPT0_CLK_SHIFT, SPEAR1340_GPT_CLK_MASK, 0,
- &_lock);
+ ARRAY_SIZE(gpt_parents), CLK_SET_RATE_NO_REPARENT,
+ SPEAR1340_PERIP_CLK_CFG, SPEAR1340_GPT0_CLK_SHIFT,
+ SPEAR1340_GPT_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "gpt0_mclk", NULL);
clk = clk_register_gate(NULL, "gpt0_clk", "gpt0_mclk", 0,
SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_GPT0_CLK_ENB, 0,
@@ -604,9 +604,9 @@ void __init spear1340_clk_init(void __iomem *misc_base)
clk_register_clkdev(clk, NULL, "gpt0");
clk = clk_register_mux(NULL, "gpt1_mclk", gpt_parents,
- ARRAY_SIZE(gpt_parents), 0, SPEAR1340_PERIP_CLK_CFG,
- SPEAR1340_GPT1_CLK_SHIFT, SPEAR1340_GPT_CLK_MASK, 0,
- &_lock);
+ ARRAY_SIZE(gpt_parents), CLK_SET_RATE_NO_REPARENT,
+ SPEAR1340_PERIP_CLK_CFG, SPEAR1340_GPT1_CLK_SHIFT,
+ SPEAR1340_GPT_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "gpt1_mclk", NULL);
clk = clk_register_gate(NULL, "gpt1_clk", "gpt1_mclk", 0,
SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_GPT1_CLK_ENB, 0,
@@ -614,9 +614,9 @@ void __init spear1340_clk_init(void __iomem *misc_base)
clk_register_clkdev(clk, NULL, "gpt1");
clk = clk_register_mux(NULL, "gpt2_mclk", gpt_parents,
- ARRAY_SIZE(gpt_parents), 0, SPEAR1340_PERIP_CLK_CFG,
- SPEAR1340_GPT2_CLK_SHIFT, SPEAR1340_GPT_CLK_MASK, 0,
- &_lock);
+ ARRAY_SIZE(gpt_parents), CLK_SET_RATE_NO_REPARENT,
+ SPEAR1340_PERIP_CLK_CFG, SPEAR1340_GPT2_CLK_SHIFT,
+ SPEAR1340_GPT_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "gpt2_mclk", NULL);
clk = clk_register_gate(NULL, "gpt2_clk", "gpt2_mclk", 0,
SPEAR1340_PERIP2_CLK_ENB, SPEAR1340_GPT2_CLK_ENB, 0,
@@ -624,9 +624,9 @@ void __init spear1340_clk_init(void __iomem *misc_base)
clk_register_clkdev(clk, NULL, "gpt2");
clk = clk_register_mux(NULL, "gpt3_mclk", gpt_parents,
- ARRAY_SIZE(gpt_parents), 0, SPEAR1340_PERIP_CLK_CFG,
- SPEAR1340_GPT3_CLK_SHIFT, SPEAR1340_GPT_CLK_MASK, 0,
- &_lock);
+ ARRAY_SIZE(gpt_parents), CLK_SET_RATE_NO_REPARENT,
+ SPEAR1340_PERIP_CLK_CFG, SPEAR1340_GPT3_CLK_SHIFT,
+ SPEAR1340_GPT_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "gpt3_mclk", NULL);
clk = clk_register_gate(NULL, "gpt3_clk", "gpt3_mclk", 0,
SPEAR1340_PERIP2_CLK_ENB, SPEAR1340_GPT3_CLK_ENB, 0,
@@ -641,7 +641,8 @@ void __init spear1340_clk_init(void __iomem *misc_base)
clk_register_clkdev(clk1, "uart0_syn_gclk", NULL);
clk = clk_register_mux(NULL, "uart0_mclk", uart0_parents,
- ARRAY_SIZE(uart0_parents), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(uart0_parents),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
SPEAR1340_PERIP_CLK_CFG, SPEAR1340_UART0_CLK_SHIFT,
SPEAR1340_UART_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "uart0_mclk", NULL);
@@ -658,9 +659,9 @@ void __init spear1340_clk_init(void __iomem *misc_base)
clk_register_clkdev(clk1, "uart1_syn_gclk", NULL);
clk = clk_register_mux(NULL, "uart1_mclk", uart1_parents,
- ARRAY_SIZE(uart1_parents), 0, SPEAR1340_PERIP_CLK_CFG,
- SPEAR1340_UART1_CLK_SHIFT, SPEAR1340_UART_CLK_MASK, 0,
- &_lock);
+ ARRAY_SIZE(uart1_parents), CLK_SET_RATE_NO_REPARENT,
+ SPEAR1340_PERIP_CLK_CFG, SPEAR1340_UART1_CLK_SHIFT,
+ SPEAR1340_UART_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "uart1_mclk", NULL);
clk = clk_register_gate(NULL, "uart1_clk", "uart1_mclk", 0,
@@ -698,7 +699,8 @@ void __init spear1340_clk_init(void __iomem *misc_base)
clk_register_clkdev(clk1, "c3_syn_gclk", NULL);
clk = clk_register_mux(NULL, "c3_mclk", c3_parents,
- ARRAY_SIZE(c3_parents), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(c3_parents),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
SPEAR1340_PERIP_CLK_CFG, SPEAR1340_C3_CLK_SHIFT,
SPEAR1340_C3_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "c3_mclk", NULL);
@@ -710,8 +712,8 @@ void __init spear1340_clk_init(void __iomem *misc_base)
/* gmac */
clk = clk_register_mux(NULL, "phy_input_mclk", gmac_phy_input_parents,
- ARRAY_SIZE(gmac_phy_input_parents), 0,
- SPEAR1340_GMAC_CLK_CFG,
+ ARRAY_SIZE(gmac_phy_input_parents),
+ CLK_SET_RATE_NO_REPARENT, SPEAR1340_GMAC_CLK_CFG,
SPEAR1340_GMAC_PHY_INPUT_CLK_SHIFT,
SPEAR1340_GMAC_PHY_INPUT_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "phy_input_mclk", NULL);
@@ -723,15 +725,16 @@ void __init spear1340_clk_init(void __iomem *misc_base)
clk_register_clkdev(clk1, "phy_syn_gclk", NULL);
clk = clk_register_mux(NULL, "phy_mclk", gmac_phy_parents,
- ARRAY_SIZE(gmac_phy_parents), 0,
+ ARRAY_SIZE(gmac_phy_parents), CLK_SET_RATE_NO_REPARENT,
SPEAR1340_PERIP_CLK_CFG, SPEAR1340_GMAC_PHY_CLK_SHIFT,
SPEAR1340_GMAC_PHY_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "stmmacphy.0", NULL);
/* clcd */
clk = clk_register_mux(NULL, "clcd_syn_mclk", clcd_synth_parents,
- ARRAY_SIZE(clcd_synth_parents), 0,
- SPEAR1340_CLCD_CLK_SYNT, SPEAR1340_CLCD_SYNT_CLK_SHIFT,
+ ARRAY_SIZE(clcd_synth_parents),
+ CLK_SET_RATE_NO_REPARENT, SPEAR1340_CLCD_CLK_SYNT,
+ SPEAR1340_CLCD_SYNT_CLK_SHIFT,
SPEAR1340_CLCD_SYNT_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "clcd_syn_mclk", NULL);
@@ -741,7 +744,8 @@ void __init spear1340_clk_init(void __iomem *misc_base)
clk_register_clkdev(clk, "clcd_syn_clk", NULL);
clk = clk_register_mux(NULL, "clcd_pixel_mclk", clcd_pixel_parents,
- ARRAY_SIZE(clcd_pixel_parents), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(clcd_pixel_parents),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
SPEAR1340_PERIP_CLK_CFG, SPEAR1340_CLCD_CLK_SHIFT,
SPEAR1340_CLCD_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "clcd_pixel_mclk", NULL);
@@ -753,9 +757,9 @@ void __init spear1340_clk_init(void __iomem *misc_base)
/* i2s */
clk = clk_register_mux(NULL, "i2s_src_mclk", i2s_src_parents,
- ARRAY_SIZE(i2s_src_parents), 0, SPEAR1340_I2S_CLK_CFG,
- SPEAR1340_I2S_SRC_CLK_SHIFT, SPEAR1340_I2S_SRC_CLK_MASK,
- 0, &_lock);
+ ARRAY_SIZE(i2s_src_parents), CLK_SET_RATE_NO_REPARENT,
+ SPEAR1340_I2S_CLK_CFG, SPEAR1340_I2S_SRC_CLK_SHIFT,
+ SPEAR1340_I2S_SRC_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "i2s_src_mclk", NULL);
clk = clk_register_aux("i2s_prs1_clk", NULL, "i2s_src_mclk",
@@ -765,7 +769,8 @@ void __init spear1340_clk_init(void __iomem *misc_base)
clk_register_clkdev(clk, "i2s_prs1_clk", NULL);
clk = clk_register_mux(NULL, "i2s_ref_mclk", i2s_ref_parents,
- ARRAY_SIZE(i2s_ref_parents), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(i2s_ref_parents),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
SPEAR1340_I2S_CLK_CFG, SPEAR1340_I2S_REF_SHIFT,
SPEAR1340_I2S_REF_SEL_MASK, 0, &_lock);
clk_register_clkdev(clk, "i2s_ref_mclk", NULL);
@@ -891,13 +896,15 @@ void __init spear1340_clk_init(void __iomem *misc_base)
/* RAS clks */
clk = clk_register_mux(NULL, "gen_syn0_1_mclk", gen_synth0_1_parents,
- ARRAY_SIZE(gen_synth0_1_parents), 0, SPEAR1340_PLL_CFG,
+ ARRAY_SIZE(gen_synth0_1_parents),
+ CLK_SET_RATE_NO_REPARENT, SPEAR1340_PLL_CFG,
SPEAR1340_GEN_SYNT0_1_CLK_SHIFT,
SPEAR1340_GEN_SYNT_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "gen_syn0_1_mclk", NULL);
clk = clk_register_mux(NULL, "gen_syn2_3_mclk", gen_synth2_3_parents,
- ARRAY_SIZE(gen_synth2_3_parents), 0, SPEAR1340_PLL_CFG,
+ ARRAY_SIZE(gen_synth2_3_parents),
+ CLK_SET_RATE_NO_REPARENT, SPEAR1340_PLL_CFG,
SPEAR1340_GEN_SYNT2_3_CLK_SHIFT,
SPEAR1340_GEN_SYNT_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "gen_syn2_3_mclk", NULL);
@@ -938,7 +945,8 @@ void __init spear1340_clk_init(void __iomem *misc_base)
clk_register_clkdev(clk, NULL, "spear_cec.1");
clk = clk_register_mux(NULL, "spdif_out_mclk", spdif_out_parents,
- ARRAY_SIZE(spdif_out_parents), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(spdif_out_parents),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
SPEAR1340_PERIP_CLK_CFG, SPEAR1340_SPDIF_OUT_CLK_SHIFT,
SPEAR1340_SPDIF_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "spdif_out_mclk", NULL);
@@ -949,7 +957,8 @@ void __init spear1340_clk_init(void __iomem *misc_base)
clk_register_clkdev(clk, NULL, "d0000000.spdif-out");
clk = clk_register_mux(NULL, "spdif_in_mclk", spdif_in_parents,
- ARRAY_SIZE(spdif_in_parents), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(spdif_in_parents),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
SPEAR1340_PERIP_CLK_CFG, SPEAR1340_SPDIF_IN_CLK_SHIFT,
SPEAR1340_SPDIF_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "spdif_in_mclk", NULL);
diff --git a/drivers/clk/spear/spear3xx_clock.c b/drivers/clk/spear/spear3xx_clock.c
index 080c3c5e33f6..c2d204315546 100644
--- a/drivers/clk/spear/spear3xx_clock.c
+++ b/drivers/clk/spear/spear3xx_clock.c
@@ -294,7 +294,8 @@ static void __init spear320_clk_init(void __iomem *soc_config_base)
clk_register_clkdev(clk, NULL, "a9400000.i2s");
clk = clk_register_mux(NULL, "i2s_ref_clk", i2s_ref_parents,
- ARRAY_SIZE(i2s_ref_parents), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(i2s_ref_parents),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
SPEAR320_CONTROL_REG, I2S_REF_PCLK_SHIFT,
I2S_REF_PCLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "i2s_ref_clk", NULL);
@@ -313,57 +314,66 @@ static void __init spear320_clk_init(void __iomem *soc_config_base)
clk_register_clkdev(clk, "hclk", "ab000000.eth");
clk = clk_register_mux(NULL, "rs485_clk", uartx_parents,
- ARRAY_SIZE(uartx_parents), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(uartx_parents),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
SPEAR320_EXT_CTRL_REG, SPEAR320_RS485_PCLK_SHIFT,
SPEAR320_UARTX_PCLK_MASK, 0, &_lock);
clk_register_clkdev(clk, NULL, "a9300000.serial");
clk = clk_register_mux(NULL, "sdhci_clk", sdhci_parents,
- ARRAY_SIZE(sdhci_parents), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(sdhci_parents),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
SPEAR320_CONTROL_REG, SDHCI_PCLK_SHIFT, SDHCI_PCLK_MASK,
0, &_lock);
clk_register_clkdev(clk, NULL, "70000000.sdhci");
clk = clk_register_mux(NULL, "smii_pclk", smii0_parents,
- ARRAY_SIZE(smii0_parents), 0, SPEAR320_CONTROL_REG,
- SMII_PCLK_SHIFT, SMII_PCLK_MASK, 0, &_lock);
+ ARRAY_SIZE(smii0_parents), CLK_SET_RATE_NO_REPARENT,
+ SPEAR320_CONTROL_REG, SMII_PCLK_SHIFT, SMII_PCLK_MASK,
+ 0, &_lock);
clk_register_clkdev(clk, NULL, "smii_pclk");
clk = clk_register_fixed_factor(NULL, "smii_clk", "smii_pclk", 0, 1, 1);
clk_register_clkdev(clk, NULL, "smii");
clk = clk_register_mux(NULL, "uart1_clk", uartx_parents,
- ARRAY_SIZE(uartx_parents), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(uartx_parents),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
SPEAR320_CONTROL_REG, UART1_PCLK_SHIFT, UART1_PCLK_MASK,
0, &_lock);
clk_register_clkdev(clk, NULL, "a3000000.serial");
clk = clk_register_mux(NULL, "uart2_clk", uartx_parents,
- ARRAY_SIZE(uartx_parents), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(uartx_parents),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
SPEAR320_EXT_CTRL_REG, SPEAR320_UART2_PCLK_SHIFT,
SPEAR320_UARTX_PCLK_MASK, 0, &_lock);
clk_register_clkdev(clk, NULL, "a4000000.serial");
clk = clk_register_mux(NULL, "uart3_clk", uartx_parents,
- ARRAY_SIZE(uartx_parents), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(uartx_parents),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
SPEAR320_EXT_CTRL_REG, SPEAR320_UART3_PCLK_SHIFT,
SPEAR320_UARTX_PCLK_MASK, 0, &_lock);
clk_register_clkdev(clk, NULL, "a9100000.serial");
clk = clk_register_mux(NULL, "uart4_clk", uartx_parents,
- ARRAY_SIZE(uartx_parents), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(uartx_parents),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
SPEAR320_EXT_CTRL_REG, SPEAR320_UART4_PCLK_SHIFT,
SPEAR320_UARTX_PCLK_MASK, 0, &_lock);
clk_register_clkdev(clk, NULL, "a9200000.serial");
clk = clk_register_mux(NULL, "uart5_clk", uartx_parents,
- ARRAY_SIZE(uartx_parents), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(uartx_parents),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
SPEAR320_EXT_CTRL_REG, SPEAR320_UART5_PCLK_SHIFT,
SPEAR320_UARTX_PCLK_MASK, 0, &_lock);
clk_register_clkdev(clk, NULL, "60000000.serial");
clk = clk_register_mux(NULL, "uart6_clk", uartx_parents,
- ARRAY_SIZE(uartx_parents), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(uartx_parents),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
SPEAR320_EXT_CTRL_REG, SPEAR320_UART6_PCLK_SHIFT,
SPEAR320_UARTX_PCLK_MASK, 0, &_lock);
clk_register_clkdev(clk, NULL, "60100000.serial");
@@ -427,7 +437,8 @@ void __init spear3xx_clk_init(void __iomem *misc_base, void __iomem *soc_config_
clk_register_clkdev(clk1, "uart_syn_gclk", NULL);
clk = clk_register_mux(NULL, "uart0_mclk", uart0_parents,
- ARRAY_SIZE(uart0_parents), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(uart0_parents),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
PERIP_CLK_CFG, UART_CLK_SHIFT, UART_CLK_MASK, 0,
&_lock);
clk_register_clkdev(clk, "uart0_mclk", NULL);
@@ -444,7 +455,8 @@ void __init spear3xx_clk_init(void __iomem *misc_base, void __iomem *soc_config_
clk_register_clkdev(clk1, "firda_syn_gclk", NULL);
clk = clk_register_mux(NULL, "firda_mclk", firda_parents,
- ARRAY_SIZE(firda_parents), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(firda_parents),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
PERIP_CLK_CFG, FIRDA_CLK_SHIFT, FIRDA_CLK_MASK, 0,
&_lock);
clk_register_clkdev(clk, "firda_mclk", NULL);
@@ -458,14 +470,16 @@ void __init spear3xx_clk_init(void __iomem *misc_base, void __iomem *soc_config_
clk_register_gpt("gpt0_syn_clk", "pll1_clk", 0, PRSC0_CLK_CFG, gpt_rtbl,
ARRAY_SIZE(gpt_rtbl), &_lock);
clk = clk_register_mux(NULL, "gpt0_clk", gpt0_parents,
- ARRAY_SIZE(gpt0_parents), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(gpt0_parents),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
PERIP_CLK_CFG, GPT0_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, NULL, "gpt0");
clk_register_gpt("gpt1_syn_clk", "pll1_clk", 0, PRSC1_CLK_CFG, gpt_rtbl,
ARRAY_SIZE(gpt_rtbl), &_lock);
clk = clk_register_mux(NULL, "gpt1_mclk", gpt1_parents,
- ARRAY_SIZE(gpt1_parents), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(gpt1_parents),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
PERIP_CLK_CFG, GPT1_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "gpt1_mclk", NULL);
clk = clk_register_gate(NULL, "gpt1_clk", "gpt1_mclk",
@@ -476,7 +490,8 @@ void __init spear3xx_clk_init(void __iomem *misc_base, void __iomem *soc_config_
clk_register_gpt("gpt2_syn_clk", "pll1_clk", 0, PRSC2_CLK_CFG, gpt_rtbl,
ARRAY_SIZE(gpt_rtbl), &_lock);
clk = clk_register_mux(NULL, "gpt2_mclk", gpt2_parents,
- ARRAY_SIZE(gpt2_parents), CLK_SET_RATE_PARENT,
+ ARRAY_SIZE(gpt2_parents),
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
PERIP_CLK_CFG, GPT2_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "gpt2_mclk", NULL);
clk = clk_register_gate(NULL, "gpt2_clk", "gpt2_mclk",
@@ -498,9 +513,9 @@ void __init spear3xx_clk_init(void __iomem *misc_base, void __iomem *soc_config_
clk_register_clkdev(clk1, "gen1_syn_gclk", NULL);
clk = clk_register_mux(NULL, "gen2_3_par_clk", gen2_3_parents,
- ARRAY_SIZE(gen2_3_parents), 0, CORE_CLK_CFG,
- GEN_SYNTH2_3_CLK_SHIFT, GEN_SYNTH2_3_CLK_MASK, 0,
- &_lock);
+ ARRAY_SIZE(gen2_3_parents), CLK_SET_RATE_NO_REPARENT,
+ CORE_CLK_CFG, GEN_SYNTH2_3_CLK_SHIFT,
+ GEN_SYNTH2_3_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "gen2_3_par_clk", NULL);
clk = clk_register_aux("gen2_syn_clk", "gen2_syn_gclk",
@@ -540,8 +555,8 @@ void __init spear3xx_clk_init(void __iomem *misc_base, void __iomem *soc_config_
clk_register_clkdev(clk, "ahbmult2_clk", NULL);
clk = clk_register_mux(NULL, "ddr_clk", ddr_parents,
- ARRAY_SIZE(ddr_parents), 0, PLL_CLK_CFG, MCTR_CLK_SHIFT,
- MCTR_CLK_MASK, 0, &_lock);
+ ARRAY_SIZE(ddr_parents), CLK_SET_RATE_NO_REPARENT,
+ PLL_CLK_CFG, MCTR_CLK_SHIFT, MCTR_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "ddr_clk", NULL);
clk = clk_register_divider(NULL, "apb_clk", "ahb_clk",
diff --git a/drivers/clk/spear/spear6xx_clock.c b/drivers/clk/spear/spear6xx_clock.c
index 9406f2426d64..4f649c9cb094 100644
--- a/drivers/clk/spear/spear6xx_clock.c
+++ b/drivers/clk/spear/spear6xx_clock.c
@@ -169,8 +169,9 @@ void __init spear6xx_clk_init(void __iomem *misc_base)
clk_register_clkdev(clk1, "uart_syn_gclk", NULL);
clk = clk_register_mux(NULL, "uart_mclk", uart_parents,
- ARRAY_SIZE(uart_parents), 0, PERIP_CLK_CFG,
- UART_CLK_SHIFT, UART_CLK_MASK, 0, &_lock);
+ ARRAY_SIZE(uart_parents), CLK_SET_RATE_NO_REPARENT,
+ PERIP_CLK_CFG, UART_CLK_SHIFT, UART_CLK_MASK, 0,
+ &_lock);
clk_register_clkdev(clk, "uart_mclk", NULL);
clk = clk_register_gate(NULL, "uart0", "uart_mclk", 0, PERIP1_CLK_ENB,
@@ -188,8 +189,9 @@ void __init spear6xx_clk_init(void __iomem *misc_base)
clk_register_clkdev(clk1, "firda_syn_gclk", NULL);
clk = clk_register_mux(NULL, "firda_mclk", firda_parents,
- ARRAY_SIZE(firda_parents), 0, PERIP_CLK_CFG,
- FIRDA_CLK_SHIFT, FIRDA_CLK_MASK, 0, &_lock);
+ ARRAY_SIZE(firda_parents), CLK_SET_RATE_NO_REPARENT,
+ PERIP_CLK_CFG, FIRDA_CLK_SHIFT, FIRDA_CLK_MASK, 0,
+ &_lock);
clk_register_clkdev(clk, "firda_mclk", NULL);
clk = clk_register_gate(NULL, "firda_clk", "firda_mclk", 0,
@@ -203,8 +205,9 @@ void __init spear6xx_clk_init(void __iomem *misc_base)
clk_register_clkdev(clk1, "clcd_syn_gclk", NULL);
clk = clk_register_mux(NULL, "clcd_mclk", clcd_parents,
- ARRAY_SIZE(clcd_parents), 0, PERIP_CLK_CFG,
- CLCD_CLK_SHIFT, CLCD_CLK_MASK, 0, &_lock);
+ ARRAY_SIZE(clcd_parents), CLK_SET_RATE_NO_REPARENT,
+ PERIP_CLK_CFG, CLCD_CLK_SHIFT, CLCD_CLK_MASK, 0,
+ &_lock);
clk_register_clkdev(clk, "clcd_mclk", NULL);
clk = clk_register_gate(NULL, "clcd_clk", "clcd_mclk", 0,
@@ -217,13 +220,13 @@ void __init spear6xx_clk_init(void __iomem *misc_base)
clk_register_clkdev(clk, "gpt0_1_syn_clk", NULL);
clk = clk_register_mux(NULL, "gpt0_mclk", gpt0_1_parents,
- ARRAY_SIZE(gpt0_1_parents), 0, PERIP_CLK_CFG,
- GPT0_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock);
+ ARRAY_SIZE(gpt0_1_parents), CLK_SET_RATE_NO_REPARENT,
+ PERIP_CLK_CFG, GPT0_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, NULL, "gpt0");
clk = clk_register_mux(NULL, "gpt1_mclk", gpt0_1_parents,
- ARRAY_SIZE(gpt0_1_parents), 0, PERIP_CLK_CFG,
- GPT1_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock);
+ ARRAY_SIZE(gpt0_1_parents), CLK_SET_RATE_NO_REPARENT,
+ PERIP_CLK_CFG, GPT1_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "gpt1_mclk", NULL);
clk = clk_register_gate(NULL, "gpt1_clk", "gpt1_mclk", 0,
@@ -235,8 +238,8 @@ void __init spear6xx_clk_init(void __iomem *misc_base)
clk_register_clkdev(clk, "gpt2_syn_clk", NULL);
clk = clk_register_mux(NULL, "gpt2_mclk", gpt2_parents,
- ARRAY_SIZE(gpt2_parents), 0, PERIP_CLK_CFG,
- GPT2_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock);
+ ARRAY_SIZE(gpt2_parents), CLK_SET_RATE_NO_REPARENT,
+ PERIP_CLK_CFG, GPT2_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "gpt2_mclk", NULL);
clk = clk_register_gate(NULL, "gpt2_clk", "gpt2_mclk", 0,
@@ -248,8 +251,8 @@ void __init spear6xx_clk_init(void __iomem *misc_base)
clk_register_clkdev(clk, "gpt3_syn_clk", NULL);
clk = clk_register_mux(NULL, "gpt3_mclk", gpt3_parents,
- ARRAY_SIZE(gpt3_parents), 0, PERIP_CLK_CFG,
- GPT3_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock);
+ ARRAY_SIZE(gpt3_parents), CLK_SET_RATE_NO_REPARENT,
+ PERIP_CLK_CFG, GPT3_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "gpt3_mclk", NULL);
clk = clk_register_gate(NULL, "gpt3_clk", "gpt3_mclk", 0,
@@ -277,8 +280,8 @@ void __init spear6xx_clk_init(void __iomem *misc_base)
clk_register_clkdev(clk, "ahbmult2_clk", NULL);
clk = clk_register_mux(NULL, "ddr_clk", ddr_parents,
- ARRAY_SIZE(ddr_parents), 0, PLL_CLK_CFG, MCTR_CLK_SHIFT,
- MCTR_CLK_MASK, 0, &_lock);
+ ARRAY_SIZE(ddr_parents), CLK_SET_RATE_NO_REPARENT,
+ PLL_CLK_CFG, MCTR_CLK_SHIFT, MCTR_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "ddr_clk", NULL);
clk = clk_register_divider(NULL, "apb_clk", "ahb_clk",
diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c
index 075db0c99edb..a0eaeb22b4f2 100644
--- a/drivers/clk/tegra/clk-tegra20.c
+++ b/drivers/clk/tegra/clk-tegra20.c
@@ -778,7 +778,8 @@ static void __init tegra20_audio_clk_init(void)
/* audio */
clk = clk_register_mux(NULL, "audio_mux", audio_parents,
- ARRAY_SIZE(audio_parents), 0,
+ ARRAY_SIZE(audio_parents),
+ CLK_SET_RATE_NO_REPARENT,
clk_base + AUDIO_SYNC_CLK, 0, 3, 0, NULL);
clk = clk_register_gate(NULL, "audio", "audio_mux", 0,
clk_base + AUDIO_SYNC_CLK, 4,
@@ -941,7 +942,8 @@ static void __init tegra20_periph_clk_init(void)
/* emc */
clk = clk_register_mux(NULL, "emc_mux", mux_pllmcp_clkm,
- ARRAY_SIZE(mux_pllmcp_clkm), 0,
+ ARRAY_SIZE(mux_pllmcp_clkm),
+ CLK_SET_RATE_NO_REPARENT,
clk_base + CLK_SOURCE_EMC,
30, 2, 0, NULL);
clk = tegra_clk_register_periph_gate("emc", "emc_mux", 0, clk_base, 0,
diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c
index ba99e3844106..082903e2fe26 100644
--- a/drivers/clk/tegra/clk-tegra30.c
+++ b/drivers/clk/tegra/clk-tegra30.c
@@ -1008,7 +1008,8 @@ static void __init tegra30_pll_init(void)
/* PLLE */
clk = clk_register_mux(NULL, "pll_e_mux", pll_e_parents,
- ARRAY_SIZE(pll_e_parents), 0,
+ ARRAY_SIZE(pll_e_parents),
+ CLK_SET_RATE_NO_REPARENT,
clk_base + PLLE_AUX, 2, 1, 0, NULL);
clk = tegra_clk_register_plle("pll_e", "pll_e_mux", clk_base, pmc_base,
CLK_GET_RATE_NOCACHE, 100000000, &pll_e_params,
@@ -1068,7 +1069,8 @@ static void __init tegra30_audio_clk_init(void)
/* audio0 */
clk = clk_register_mux(NULL, "audio0_mux", mux_audio_sync_clk,
- ARRAY_SIZE(mux_audio_sync_clk), 0,
+ ARRAY_SIZE(mux_audio_sync_clk),
+ CLK_SET_RATE_NO_REPARENT,
clk_base + AUDIO_SYNC_CLK_I2S0, 0, 3, 0, NULL);
clk = clk_register_gate(NULL, "audio0", "audio0_mux", 0,
clk_base + AUDIO_SYNC_CLK_I2S0, 4,
@@ -1078,7 +1080,8 @@ static void __init tegra30_audio_clk_init(void)
/* audio1 */
clk = clk_register_mux(NULL, "audio1_mux", mux_audio_sync_clk,
- ARRAY_SIZE(mux_audio_sync_clk), 0,
+ ARRAY_SIZE(mux_audio_sync_clk),
+ CLK_SET_RATE_NO_REPARENT,
clk_base + AUDIO_SYNC_CLK_I2S1, 0, 3, 0, NULL);
clk = clk_register_gate(NULL, "audio1", "audio1_mux", 0,
clk_base + AUDIO_SYNC_CLK_I2S1, 4,
@@ -1088,7 +1091,8 @@ static void __init tegra30_audio_clk_init(void)
/* audio2 */
clk = clk_register_mux(NULL, "audio2_mux", mux_audio_sync_clk,
- ARRAY_SIZE(mux_audio_sync_clk), 0,
+ ARRAY_SIZE(mux_audio_sync_clk),
+ CLK_SET_RATE_NO_REPARENT,
clk_base + AUDIO_SYNC_CLK_I2S2, 0, 3, 0, NULL);
clk = clk_register_gate(NULL, "audio2", "audio2_mux", 0,
clk_base + AUDIO_SYNC_CLK_I2S2, 4,
@@ -1098,7 +1102,8 @@ static void __init tegra30_audio_clk_init(void)
/* audio3 */
clk = clk_register_mux(NULL, "audio3_mux", mux_audio_sync_clk,
- ARRAY_SIZE(mux_audio_sync_clk), 0,
+ ARRAY_SIZE(mux_audio_sync_clk),
+ CLK_SET_RATE_NO_REPARENT,
clk_base + AUDIO_SYNC_CLK_I2S3, 0, 3, 0, NULL);
clk = clk_register_gate(NULL, "audio3", "audio3_mux", 0,
clk_base + AUDIO_SYNC_CLK_I2S3, 4,
@@ -1108,7 +1113,8 @@ static void __init tegra30_audio_clk_init(void)
/* audio4 */
clk = clk_register_mux(NULL, "audio4_mux", mux_audio_sync_clk,
- ARRAY_SIZE(mux_audio_sync_clk), 0,
+ ARRAY_SIZE(mux_audio_sync_clk),
+ CLK_SET_RATE_NO_REPARENT,
clk_base + AUDIO_SYNC_CLK_I2S4, 0, 3, 0, NULL);
clk = clk_register_gate(NULL, "audio4", "audio4_mux", 0,
clk_base + AUDIO_SYNC_CLK_I2S4, 4,
@@ -1118,7 +1124,8 @@ static void __init tegra30_audio_clk_init(void)
/* spdif */
clk = clk_register_mux(NULL, "spdif_mux", mux_audio_sync_clk,
- ARRAY_SIZE(mux_audio_sync_clk), 0,
+ ARRAY_SIZE(mux_audio_sync_clk),
+ CLK_SET_RATE_NO_REPARENT,
clk_base + AUDIO_SYNC_CLK_SPDIF, 0, 3, 0, NULL);
clk = clk_register_gate(NULL, "spdif", "spdif_mux", 0,
clk_base + AUDIO_SYNC_CLK_SPDIF, 4,
@@ -1211,7 +1218,8 @@ static void __init tegra30_pmc_clk_init(void)
/* clk_out_1 */
clk = clk_register_mux(NULL, "clk_out_1_mux", clk_out1_parents,
- ARRAY_SIZE(clk_out1_parents), 0,
+ ARRAY_SIZE(clk_out1_parents),
+ CLK_SET_RATE_NO_REPARENT,
pmc_base + PMC_CLK_OUT_CNTRL, 6, 3, 0,
&clk_out_lock);
clks[clk_out_1_mux] = clk;
@@ -1223,7 +1231,8 @@ static void __init tegra30_pmc_clk_init(void)
/* clk_out_2 */
clk = clk_register_mux(NULL, "clk_out_2_mux", clk_out2_parents,
- ARRAY_SIZE(clk_out1_parents), 0,
+ ARRAY_SIZE(clk_out1_parents),
+ CLK_SET_RATE_NO_REPARENT,
pmc_base + PMC_CLK_OUT_CNTRL, 14, 3, 0,
&clk_out_lock);
clk = clk_register_gate(NULL, "clk_out_2", "clk_out_2_mux", 0,
@@ -1234,7 +1243,8 @@ static void __init tegra30_pmc_clk_init(void)
/* clk_out_3 */
clk = clk_register_mux(NULL, "clk_out_3_mux", clk_out3_parents,
- ARRAY_SIZE(clk_out1_parents), 0,
+ ARRAY_SIZE(clk_out1_parents),
+ CLK_SET_RATE_NO_REPARENT,
pmc_base + PMC_CLK_OUT_CNTRL, 22, 3, 0,
&clk_out_lock);
clk = clk_register_gate(NULL, "clk_out_3", "clk_out_3_mux", 0,
@@ -1661,7 +1671,8 @@ static void __init tegra30_periph_clk_init(void)
/* emc */
clk = clk_register_mux(NULL, "emc_mux", mux_pllmcp_clkm,
- ARRAY_SIZE(mux_pllmcp_clkm), 0,
+ ARRAY_SIZE(mux_pllmcp_clkm),
+ CLK_SET_RATE_NO_REPARENT,
clk_base + CLK_SOURCE_EMC,
30, 2, 0, NULL);
clk = tegra_clk_register_periph_gate("emc", "emc_mux", 0, clk_base, 0,
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index e9924898043a..6f286897359c 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -312,6 +312,15 @@ config MMP_PDMA
help
Support the MMP PDMA engine for PXA and MMP platfrom.
+config K3_DMA
+ tristate "Hisilicon K3 DMA support"
+ depends on ARCH_HS
+ select DMA_ENGINE
+ select DMA_VIRTUAL_CHANNELS
+ help
+ Support the DMA engine for Hisilicon K3 platform
+ devices.
+
config DMA_ENGINE
bool
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index a2b0df591f95..3b05b152a4c8 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -38,3 +38,4 @@ obj-$(CONFIG_DMA_SA11X0) += sa11x0-dma.o
obj-$(CONFIG_MMP_TDMA) += mmp_tdma.o
obj-$(CONFIG_DMA_OMAP) += omap-dma.o
obj-$(CONFIG_MMP_PDMA) += mmp_pdma.o
+obj-$(CONFIG_K3_DMA) += k3dma.o
diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index 8bad254a498d..089d6a7b4732 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -83,6 +83,7 @@
#include <linux/pm_runtime.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
+#include <linux/of.h>
#include <linux/amba/pl080.h>
#include "dmaengine.h"
@@ -1718,8 +1719,10 @@ static int pl08x_dma_init_virtual_channels(struct pl08x_driver_data *pl08x,
chan->signal = -1;
if (slave) {
- chan->cd = &pl08x->pd->slave_channels[i];
- pl08x_dma_slave_init(chan);
+ if (pl08x->pd->slave_channels) {
+ chan->cd = &pl08x->pd->slave_channels[i];
+ pl08x_dma_slave_init(chan);
+ }
} else {
chan->cd = &pl08x->pd->memcpy_channel;
chan->name = kasprintf(GFP_KERNEL, "memcpy%d", i);
@@ -1841,6 +1844,25 @@ static inline void init_pl08x_debugfs(struct pl08x_driver_data *pl08x)
{
}
#endif
+static struct pl08x_platform_data *pl08x_get_pdata(struct device *dev)
+{
+ struct pl08x_platform_data *pd;
+ struct device_node *np = dev->of_node;
+
+ pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
+ if (!pd)
+ return NULL;
+ of_property_read_u32(np, "dma-requests", &pd->num_slave_channels);
+
+ pd->memcpy_channel.cctl_memcpy =
+ (PL080_BSIZE_16 << PL080_CONTROL_SB_SIZE_SHIFT |
+ PL080_BSIZE_16 << PL080_CONTROL_DB_SIZE_SHIFT |
+ PL080_WIDTH_32BIT << PL080_CONTROL_SWIDTH_SHIFT |
+ PL080_WIDTH_32BIT << PL080_CONTROL_DWIDTH_SHIFT |
+ PL080_CONTROL_PROT_BUFF | PL080_CONTROL_PROT_CACHE |
+ PL080_CONTROL_PROT_SYS);
+ return pd;
+}
static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
{
@@ -1883,7 +1905,10 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
pl08x->slave.device_control = pl08x_control;
/* Get the platform data */
- pl08x->pd = dev_get_platdata(&adev->dev);
+ if ((&adev->dev)->of_node)
+ pl08x->pd = pl08x_get_pdata(&adev->dev);
+ else
+ pl08x->pd = dev_get_platdata(&adev->dev);
if (!pl08x->pd) {
dev_err(&adev->dev, "no platform data supplied\n");
ret = -EINVAL;
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index 93f7992bee5c..78dbbe09d7b1 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -504,6 +504,32 @@ static struct dma_chan *private_candidate(const dma_cap_mask_t *mask,
}
/**
+ * dma_request_channel - try to get specific channel exclusively
+ * @chan: target channel
+ */
+struct dma_chan *dma_get_slave_channel(struct dma_chan *chan)
+{
+ int err = -EBUSY;
+
+ /* lock against __dma_request_channel */
+ mutex_lock(&dma_list_mutex);
+
+ if (chan->client_count == 0)
+ err = dma_chan_get(chan);
+ else
+ chan = NULL;
+
+ mutex_unlock(&dma_list_mutex);
+
+ if (err)
+ pr_debug("%s: failed to get %s: (%d)\n",
+ __func__, dma_chan_name(chan), err);
+
+ return chan;
+}
+EXPORT_SYMBOL_GPL(dma_get_slave_channel);
+
+/**
* dma_request_channel - try to allocate an exclusive channel
* @mask: capabilities that the channel must satisfy
* @fn: optional callback to disposition available channels
diff --git a/drivers/dma/k3dma.c b/drivers/dma/k3dma.c
new file mode 100644
index 000000000000..1ba08bb093e7
--- /dev/null
+++ b/drivers/dma/k3dma.c
@@ -0,0 +1,849 @@
+/*
+ * Copyright (c) 2013 Linaro Ltd.
+ * Copyright (c) 2013 Hisilicon Limited.
+ *
+ * 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/sched.h>
+#include <linux/device.h>
+#include <linux/dmaengine.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/clk.h>
+#include <linux/of_dma.h>
+
+#include "virt-dma.h"
+
+#define DRIVER_NAME "k3-dma"
+#define DMA_ALIGN 3
+#define DMA_MAX_SIZE 0x1ffc
+
+#define INT_STAT 0x00
+#define INT_TC1 0x04
+#define INT_ERR1 0x0c
+#define INT_ERR2 0x10
+#define INT_TC1_MASK 0x18
+#define INT_ERR1_MASK 0x20
+#define INT_ERR2_MASK 0x24
+#define INT_TC1_RAW 0x600
+#define INT_ERR1_RAW 0x608
+#define INT_ERR2_RAW 0x610
+#define CH_PRI 0x688
+#define CH_STAT 0x690
+#define CX_CUR_CNT 0x704
+#define CX_LLI 0x800
+#define CX_CNT 0x810
+#define CX_SRC 0x814
+#define CX_DST 0x818
+#define CX_CONFIG 0x81c
+#define AXI_CONFIG 0x820
+#define DEF_AXI_CONFIG 0x201201
+
+#define CX_LLI_CHAIN_EN 0x2
+#define CCFG_EN 0x1
+#define CCFG_MEM2PER (0x1 << 2)
+#define CCFG_PER2MEM (0x2 << 2)
+#define CCFG_SRCINCR (0x1 << 31)
+#define CCFG_DSTINCR (0x1 << 30)
+
+struct k3_desc_hw {
+ u32 lli;
+ u32 reserved[3];
+ u32 count;
+ u32 saddr;
+ u32 daddr;
+ u32 config;
+} __aligned(32);
+
+struct k3_dma_desc_sw {
+ struct virt_dma_desc vd;
+ dma_addr_t desc_hw_lli;
+ size_t desc_num;
+ size_t size;
+ struct k3_desc_hw desc_hw[0];
+};
+
+struct k3_dma_phy;
+
+struct k3_dma_chan {
+ u32 ccfg;
+ struct virt_dma_chan vc;
+ struct k3_dma_phy *phy;
+ struct list_head node;
+ enum dma_transfer_direction dir;
+ dma_addr_t dev_addr;
+ enum dma_status status;
+};
+
+struct k3_dma_phy {
+ u32 idx;
+ void __iomem *base;
+ struct k3_dma_chan *vchan;
+ struct k3_dma_desc_sw *ds_run;
+ struct k3_dma_desc_sw *ds_done;
+};
+
+struct k3_dma_dev {
+ struct dma_device slave;
+ void __iomem *base;
+ struct tasklet_struct task;
+ spinlock_t lock;
+ struct list_head chan_pending;
+ struct k3_dma_phy *phy;
+ struct k3_dma_chan *chans;
+ struct clk *clk;
+ u32 dma_channels;
+ u32 dma_requests;
+};
+
+#define to_k3_dma(dmadev) container_of(dmadev, struct k3_dma_dev, slave)
+
+static struct k3_dma_chan *to_k3_chan(struct dma_chan *chan)
+{
+ return container_of(chan, struct k3_dma_chan, vc.chan);
+}
+
+static void k3_dma_pause_dma(struct k3_dma_phy *phy, bool on)
+{
+ u32 val = 0;
+
+ if (on) {
+ val = readl_relaxed(phy->base + CX_CONFIG);
+ val |= CCFG_EN;
+ writel_relaxed(val, phy->base + CX_CONFIG);
+ } else {
+ val = readl_relaxed(phy->base + CX_CONFIG);
+ val &= ~CCFG_EN;
+ writel_relaxed(val, phy->base + CX_CONFIG);
+ }
+}
+
+static void k3_dma_terminate_chan(struct k3_dma_phy *phy, struct k3_dma_dev *d)
+{
+ u32 val = 0;
+
+ k3_dma_pause_dma(phy, false);
+
+ val = 0x1 << phy->idx;
+ writel_relaxed(val, d->base + INT_TC1_RAW);
+ writel_relaxed(val, d->base + INT_ERR1_RAW);
+ writel_relaxed(val, d->base + INT_ERR2_RAW);
+}
+
+static void k3_dma_set_desc(struct k3_dma_phy *phy, struct k3_desc_hw *hw)
+{
+ writel_relaxed(hw->lli, phy->base + CX_LLI);
+ writel_relaxed(hw->count, phy->base + CX_CNT);
+ writel_relaxed(hw->saddr, phy->base + CX_SRC);
+ writel_relaxed(hw->daddr, phy->base + CX_DST);
+ writel_relaxed(DEF_AXI_CONFIG, phy->base + AXI_CONFIG);
+ writel_relaxed(hw->config, phy->base + CX_CONFIG);
+}
+
+static u32 k3_dma_get_curr_cnt(struct k3_dma_dev *d, struct k3_dma_phy *phy)
+{
+ u32 cnt = 0;
+
+ cnt = readl_relaxed(d->base + CX_CUR_CNT + phy->idx * 0x10);
+ cnt &= 0xffff;
+ return cnt;
+}
+
+static u32 k3_dma_get_curr_lli(struct k3_dma_phy *phy)
+{
+ return readl_relaxed(phy->base + CX_LLI);
+}
+
+static u32 k3_dma_get_chan_stat(struct k3_dma_dev *d)
+{
+ return readl_relaxed(d->base + CH_STAT);
+}
+
+static void k3_dma_enable_dma(struct k3_dma_dev *d, bool on)
+{
+ if (on) {
+ /* set same priority */
+ writel_relaxed(0x0, d->base + CH_PRI);
+
+ /* unmask irq */
+ writel_relaxed(0xffff, d->base + INT_TC1_MASK);
+ writel_relaxed(0xffff, d->base + INT_ERR1_MASK);
+ writel_relaxed(0xffff, d->base + INT_ERR2_MASK);
+ } else {
+ /* mask irq */
+ writel_relaxed(0x0, d->base + INT_TC1_MASK);
+ writel_relaxed(0x0, d->base + INT_ERR1_MASK);
+ writel_relaxed(0x0, d->base + INT_ERR2_MASK);
+ }
+}
+
+static irqreturn_t k3_dma_int_handler(int irq, void *dev_id)
+{
+ struct k3_dma_dev *d = (struct k3_dma_dev *)dev_id;
+ struct k3_dma_phy *p;
+ struct k3_dma_chan *c;
+ u32 stat = readl_relaxed(d->base + INT_STAT);
+ u32 tc1 = readl_relaxed(d->base + INT_TC1);
+ u32 err1 = readl_relaxed(d->base + INT_ERR1);
+ u32 err2 = readl_relaxed(d->base + INT_ERR2);
+ u32 i, irq_chan = 0;
+
+ while (stat) {
+ i = __ffs(stat);
+ stat &= (stat - 1);
+ if (likely(tc1 & BIT(i))) {
+ p = &d->phy[i];
+ c = p->vchan;
+ if (c) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&c->vc.lock, flags);
+ vchan_cookie_complete(&p->ds_run->vd);
+ p->ds_done = p->ds_run;
+ spin_unlock_irqrestore(&c->vc.lock, flags);
+ }
+ irq_chan |= BIT(i);
+ }
+ if (unlikely((err1 & BIT(i)) || (err2 & BIT(i))))
+ dev_warn(d->slave.dev, "DMA ERR\n");
+ }
+
+ writel_relaxed(irq_chan, d->base + INT_TC1_RAW);
+ writel_relaxed(err1, d->base + INT_ERR1_RAW);
+ writel_relaxed(err2, d->base + INT_ERR2_RAW);
+
+ if (irq_chan) {
+ tasklet_schedule(&d->task);
+ return IRQ_HANDLED;
+ } else
+ return IRQ_NONE;
+}
+
+static int k3_dma_start_txd(struct k3_dma_chan *c)
+{
+ struct k3_dma_dev *d = to_k3_dma(c->vc.chan.device);
+ struct virt_dma_desc *vd = vchan_next_desc(&c->vc);
+
+ if (!c->phy)
+ return -EAGAIN;
+
+ if (BIT(c->phy->idx) & k3_dma_get_chan_stat(d))
+ return -EAGAIN;
+
+ if (vd) {
+ struct k3_dma_desc_sw *ds =
+ container_of(vd, struct k3_dma_desc_sw, vd);
+ /*
+ * fetch and remove request from vc->desc_issued
+ * so vc->desc_issued only contains desc pending
+ */
+ list_del(&ds->vd.node);
+ c->phy->ds_run = ds;
+ c->phy->ds_done = NULL;
+ /* start dma */
+ k3_dma_set_desc(c->phy, &ds->desc_hw[0]);
+ return 0;
+ }
+ c->phy->ds_done = NULL;
+ c->phy->ds_run = NULL;
+ return -EAGAIN;
+}
+
+static void k3_dma_tasklet(unsigned long arg)
+{
+ struct k3_dma_dev *d = (struct k3_dma_dev *)arg;
+ struct k3_dma_phy *p;
+ struct k3_dma_chan *c, *cn;
+ unsigned pch, pch_alloc = 0;
+
+ /* check new dma request of running channel in vc->desc_issued */
+ list_for_each_entry_safe(c, cn, &d->slave.channels, vc.chan.device_node) {
+ spin_lock_irq(&c->vc.lock);
+ p = c->phy;
+ if (p && p->ds_done) {
+ if (k3_dma_start_txd(c)) {
+ /* No current txd associated with this channel */
+ dev_dbg(d->slave.dev, "pchan %u: free\n", p->idx);
+ /* Mark this channel free */
+ c->phy = NULL;
+ p->vchan = NULL;
+ }
+ }
+ spin_unlock_irq(&c->vc.lock);
+ }
+
+ /* check new channel request in d->chan_pending */
+ spin_lock_irq(&d->lock);
+ for (pch = 0; pch < d->dma_channels; pch++) {
+ p = &d->phy[pch];
+
+ if (p->vchan == NULL && !list_empty(&d->chan_pending)) {
+ c = list_first_entry(&d->chan_pending,
+ struct k3_dma_chan, node);
+ /* remove from d->chan_pending */
+ list_del_init(&c->node);
+ pch_alloc |= 1 << pch;
+ /* Mark this channel allocated */
+ p->vchan = c;
+ c->phy = p;
+ dev_dbg(d->slave.dev, "pchan %u: alloc vchan %p\n", pch, &c->vc);
+ }
+ }
+ spin_unlock_irq(&d->lock);
+
+ for (pch = 0; pch < d->dma_channels; pch++) {
+ if (pch_alloc & (1 << pch)) {
+ p = &d->phy[pch];
+ c = p->vchan;
+ if (c) {
+ spin_lock_irq(&c->vc.lock);
+ k3_dma_start_txd(c);
+ spin_unlock_irq(&c->vc.lock);
+ }
+ }
+ }
+}
+
+static int k3_dma_alloc_chan_resources(struct dma_chan *chan)
+{
+ return 0;
+}
+
+static void k3_dma_free_chan_resources(struct dma_chan *chan)
+{
+ struct k3_dma_chan *c = to_k3_chan(chan);
+ struct k3_dma_dev *d = to_k3_dma(chan->device);
+ unsigned long flags;
+
+ spin_lock_irqsave(&d->lock, flags);
+ list_del_init(&c->node);
+ spin_unlock_irqrestore(&d->lock, flags);
+
+ vchan_free_chan_resources(&c->vc);
+ c->ccfg = 0;
+}
+
+static enum dma_status k3_dma_tx_status(struct dma_chan *chan,
+ dma_cookie_t cookie, struct dma_tx_state *state)
+{
+ struct k3_dma_chan *c = to_k3_chan(chan);
+ struct k3_dma_dev *d = to_k3_dma(chan->device);
+ struct k3_dma_phy *p;
+ struct virt_dma_desc *vd;
+ unsigned long flags;
+ enum dma_status ret;
+ size_t bytes = 0;
+
+ ret = dma_cookie_status(&c->vc.chan, cookie, state);
+ if (ret == DMA_SUCCESS)
+ return ret;
+
+ spin_lock_irqsave(&c->vc.lock, flags);
+ p = c->phy;
+ ret = c->status;
+
+ /*
+ * If the cookie is on our issue queue, then the residue is
+ * its total size.
+ */
+ vd = vchan_find_desc(&c->vc, cookie);
+ if (vd) {
+ bytes = container_of(vd, struct k3_dma_desc_sw, vd)->size;
+ } else if ((!p) || (!p->ds_run)) {
+ bytes = 0;
+ } else {
+ struct k3_dma_desc_sw *ds = p->ds_run;
+ u32 clli = 0, index = 0;
+
+ bytes = k3_dma_get_curr_cnt(d, p);
+ clli = k3_dma_get_curr_lli(p);
+ index = (clli - ds->desc_hw_lli) / sizeof(struct k3_desc_hw);
+ for (; index < ds->desc_num; index++) {
+ bytes += ds->desc_hw[index].count;
+ /* end of lli */
+ if (!ds->desc_hw[index].lli)
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&c->vc.lock, flags);
+ dma_set_residue(state, bytes);
+ return ret;
+}
+
+static void k3_dma_issue_pending(struct dma_chan *chan)
+{
+ struct k3_dma_chan *c = to_k3_chan(chan);
+ struct k3_dma_dev *d = to_k3_dma(chan->device);
+ unsigned long flags;
+
+ spin_lock_irqsave(&c->vc.lock, flags);
+ /* add request to vc->desc_issued */
+ if (vchan_issue_pending(&c->vc)) {
+ spin_lock(&d->lock);
+ if (!c->phy) {
+ if (list_empty(&c->node)) {
+ /* if new channel, add chan_pending */
+ list_add_tail(&c->node, &d->chan_pending);
+ /* check in tasklet */
+ tasklet_schedule(&d->task);
+ dev_dbg(d->slave.dev, "vchan %p: issued\n", &c->vc);
+ }
+ }
+ spin_unlock(&d->lock);
+ } else
+ dev_dbg(d->slave.dev, "vchan %p: nothing to issue\n", &c->vc);
+ spin_unlock_irqrestore(&c->vc.lock, flags);
+}
+
+static void k3_dma_fill_desc(struct k3_dma_desc_sw *ds, dma_addr_t dst,
+ dma_addr_t src, size_t len, u32 num, u32 ccfg)
+{
+ if ((num + 1) < ds->desc_num)
+ ds->desc_hw[num].lli = ds->desc_hw_lli + (num + 1) *
+ sizeof(struct k3_desc_hw);
+ ds->desc_hw[num].lli |= CX_LLI_CHAIN_EN;
+ ds->desc_hw[num].count = len;
+ ds->desc_hw[num].saddr = src;
+ ds->desc_hw[num].daddr = dst;
+ ds->desc_hw[num].config = ccfg;
+}
+
+static struct dma_async_tx_descriptor *k3_dma_prep_memcpy(
+ struct dma_chan *chan, dma_addr_t dst, dma_addr_t src,
+ size_t len, unsigned long flags)
+{
+ struct k3_dma_chan *c = to_k3_chan(chan);
+ struct k3_dma_desc_sw *ds;
+ size_t copy = 0;
+ int num = 0;
+
+ if (!len)
+ return NULL;
+
+ num = DIV_ROUND_UP(len, DMA_MAX_SIZE);
+ ds = kzalloc(sizeof(*ds) + num * sizeof(ds->desc_hw[0]), GFP_ATOMIC);
+ if (!ds) {
+ dev_dbg(chan->device->dev, "vchan %p: kzalloc fail\n", &c->vc);
+ return NULL;
+ }
+ ds->desc_hw_lli = __virt_to_phys((unsigned long)&ds->desc_hw[0]);
+ ds->size = len;
+ ds->desc_num = num;
+ num = 0;
+
+ if (!c->ccfg) {
+ /* default is memtomem, without calling device_control */
+ c->ccfg = CCFG_SRCINCR | CCFG_DSTINCR | CCFG_EN;
+ c->ccfg |= (0xf << 20) | (0xf << 24); /* burst = 16 */
+ c->ccfg |= (0x3 << 12) | (0x3 << 16); /* width = 64 bit */
+ }
+
+ do {
+ copy = min_t(size_t, len, DMA_MAX_SIZE);
+ k3_dma_fill_desc(ds, dst, src, copy, num++, c->ccfg);
+
+ if (c->dir == DMA_MEM_TO_DEV) {
+ src += copy;
+ } else if (c->dir == DMA_DEV_TO_MEM) {
+ dst += copy;
+ } else {
+ src += copy;
+ dst += copy;
+ }
+ len -= copy;
+ } while (len);
+
+ ds->desc_hw[num-1].lli = 0; /* end of link */
+ return vchan_tx_prep(&c->vc, &ds->vd, flags);
+}
+
+static struct dma_async_tx_descriptor *k3_dma_prep_slave_sg(
+ struct dma_chan *chan, struct scatterlist *sgl, unsigned int sglen,
+ enum dma_transfer_direction dir, unsigned long flags, void *context)
+{
+ struct k3_dma_chan *c = to_k3_chan(chan);
+ struct k3_dma_desc_sw *ds;
+ size_t len, avail, total = 0;
+ struct scatterlist *sg;
+ dma_addr_t addr, src = 0, dst = 0;
+ int num = sglen, i;
+
+ if (sgl == 0)
+ return NULL;
+
+ for_each_sg(sgl, sg, sglen, i) {
+ avail = sg_dma_len(sg);
+ if (avail > DMA_MAX_SIZE)
+ num += DIV_ROUND_UP(avail, DMA_MAX_SIZE) - 1;
+ }
+
+ ds = kzalloc(sizeof(*ds) + num * sizeof(ds->desc_hw[0]), GFP_ATOMIC);
+ if (!ds) {
+ dev_dbg(chan->device->dev, "vchan %p: kzalloc fail\n", &c->vc);
+ return NULL;
+ }
+ ds->desc_hw_lli = __virt_to_phys((unsigned long)&ds->desc_hw[0]);
+ ds->desc_num = num;
+ num = 0;
+
+ for_each_sg(sgl, sg, sglen, i) {
+ addr = sg_dma_address(sg);
+ avail = sg_dma_len(sg);
+ total += avail;
+
+ do {
+ len = min_t(size_t, avail, DMA_MAX_SIZE);
+
+ if (dir == DMA_MEM_TO_DEV) {
+ src = addr;
+ dst = c->dev_addr;
+ } else if (dir == DMA_DEV_TO_MEM) {
+ src = c->dev_addr;
+ dst = addr;
+ }
+
+ k3_dma_fill_desc(ds, dst, src, len, num++, c->ccfg);
+
+ addr += len;
+ avail -= len;
+ } while (avail);
+ }
+
+ ds->desc_hw[num-1].lli = 0; /* end of link */
+ ds->size = total;
+ return vchan_tx_prep(&c->vc, &ds->vd, flags);
+}
+
+static int k3_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
+ unsigned long arg)
+{
+ struct k3_dma_chan *c = to_k3_chan(chan);
+ struct k3_dma_dev *d = to_k3_dma(chan->device);
+ struct dma_slave_config *cfg = (void *)arg;
+ struct k3_dma_phy *p = NULL;
+ unsigned long flags;
+ u32 maxburst = 0, val = 0;
+ enum dma_slave_buswidth width = DMA_SLAVE_BUSWIDTH_UNDEFINED;
+ LIST_HEAD(head);
+
+ if (c)
+ p = c->phy;
+
+ switch (cmd) {
+ case DMA_SLAVE_CONFIG:
+ if (cfg == NULL)
+ return -EINVAL;
+ c->dir = cfg->direction;
+ if (c->dir == DMA_DEV_TO_MEM) {
+ c->ccfg = CCFG_DSTINCR;
+ c->dev_addr = cfg->src_addr;
+ maxburst = cfg->src_maxburst;
+ width = cfg->src_addr_width;
+ } else if (c->dir == DMA_MEM_TO_DEV) {
+ c->ccfg = CCFG_SRCINCR;
+ c->dev_addr = cfg->dst_addr;
+ maxburst = cfg->dst_maxburst;
+ width = cfg->dst_addr_width;
+ }
+ switch (width) {
+ case DMA_SLAVE_BUSWIDTH_1_BYTE:
+ val = 0;
+ break;
+ case DMA_SLAVE_BUSWIDTH_2_BYTES:
+ val = 1;
+ break;
+ case DMA_SLAVE_BUSWIDTH_4_BYTES:
+ val = 2;
+ break;
+ case DMA_SLAVE_BUSWIDTH_8_BYTES:
+ val = 3;
+ break;
+ default:
+ break;
+ }
+ c->ccfg |= (val << 12) | (val << 16);
+
+ if ((maxburst == 0) || (maxburst > 16))
+ val = 16;
+ else
+ val = maxburst - 1;
+ c->ccfg |= (val << 20) | (val << 24);
+ c->ccfg |= CCFG_MEM2PER | CCFG_EN;
+
+ /* specific request line */
+ c->ccfg |= c->vc.chan.chan_id << 4;
+ break;
+
+ case DMA_TERMINATE_ALL:
+ dev_dbg(d->slave.dev, "vchan %p: terminate all\n", &c->vc);
+
+ /* Prevent this channel being scheduled */
+ spin_lock(&d->lock);
+ list_del_init(&c->node);
+ spin_unlock(&d->lock);
+
+ /* Clear the tx descriptor lists */
+ spin_lock_irqsave(&c->vc.lock, flags);
+ vchan_get_all_descriptors(&c->vc, &head);
+ if (p) {
+ /* vchan is assigned to a pchan - stop the channel */
+ k3_dma_terminate_chan(p, d);
+ c->phy = NULL;
+ p->vchan = NULL;
+ p->ds_run = p->ds_done = NULL;
+ }
+ spin_unlock_irqrestore(&c->vc.lock, flags);
+ vchan_dma_desc_free_list(&c->vc, &head);
+ break;
+
+ case DMA_PAUSE:
+ dev_dbg(d->slave.dev, "vchan %p: pause\n", &c->vc);
+ if (c->status == DMA_IN_PROGRESS) {
+ c->status = DMA_PAUSED;
+ if (p) {
+ k3_dma_pause_dma(p, false);
+ } else {
+ spin_lock(&d->lock);
+ list_del_init(&c->node);
+ spin_unlock(&d->lock);
+ }
+ }
+ break;
+
+ case DMA_RESUME:
+ dev_dbg(d->slave.dev, "vchan %p: resume\n", &c->vc);
+ spin_lock_irqsave(&c->vc.lock, flags);
+ if (c->status == DMA_PAUSED) {
+ c->status = DMA_IN_PROGRESS;
+ if (p) {
+ k3_dma_pause_dma(p, true);
+ } else if (!list_empty(&c->vc.desc_issued)) {
+ spin_lock(&d->lock);
+ list_add_tail(&c->node, &d->chan_pending);
+ spin_unlock(&d->lock);
+ }
+ }
+ spin_unlock_irqrestore(&c->vc.lock, flags);
+ break;
+ default:
+ return -ENXIO;
+ }
+ return 0;
+}
+
+static void k3_dma_free_desc(struct virt_dma_desc *vd)
+{
+ struct k3_dma_desc_sw *ds =
+ container_of(vd, struct k3_dma_desc_sw, vd);
+
+ kfree(ds);
+}
+
+static struct of_device_id k3_pdma_dt_ids[] = {
+ { .compatible = "hisilicon,k3-dma-1.0", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, k3_pdma_dt_ids);
+
+static struct dma_chan *k3_of_dma_simple_xlate(struct of_phandle_args *dma_spec,
+ struct of_dma *ofdma)
+{
+ struct k3_dma_dev *d = ofdma->of_dma_data;
+ unsigned int request = dma_spec->args[0];
+
+ if (request > d->dma_requests)
+ return NULL;
+
+ return dma_get_slave_channel(&(d->chans[request].vc.chan));
+}
+
+static int k3_dma_probe(struct platform_device *op)
+{
+ struct k3_dma_dev *d;
+ const struct of_device_id *of_id;
+ struct resource *iores;
+ int i, ret, irq = 0;
+
+ iores = platform_get_resource(op, IORESOURCE_MEM, 0);
+ if (!iores)
+ return -EINVAL;
+
+ d = devm_kzalloc(&op->dev, sizeof(*d), GFP_KERNEL);
+ if (!d)
+ return -ENOMEM;
+
+ d->base = devm_request_and_ioremap(&op->dev, iores);
+ if (!d->base)
+ return -EADDRNOTAVAIL;
+
+ of_id = of_match_device(k3_pdma_dt_ids, &op->dev);
+ if (of_id) {
+ of_property_read_u32((&op->dev)->of_node,
+ "dma-channels", &d->dma_channels);
+ of_property_read_u32((&op->dev)->of_node,
+ "dma-requests", &d->dma_requests);
+ }
+
+ d->clk = devm_clk_get(&op->dev, NULL);
+ if (IS_ERR(d->clk)) {
+ dev_err(&op->dev, "no dma clk\n");
+ return PTR_ERR(d->clk);
+ }
+
+ irq = platform_get_irq(op, 0);
+ ret = devm_request_irq(&op->dev, irq,
+ k3_dma_int_handler, IRQF_DISABLED, DRIVER_NAME, d);
+ if (ret)
+ return ret;
+
+ /* init phy channel */
+ d->phy = devm_kzalloc(&op->dev,
+ d->dma_channels * sizeof(struct k3_dma_phy), GFP_KERNEL);
+ if (d->phy == NULL)
+ return -ENOMEM;
+
+ for (i = 0; i < d->dma_channels; i++) {
+ struct k3_dma_phy *p = &d->phy[i];
+
+ p->idx = i;
+ p->base = d->base + i * 0x40;
+ }
+
+ INIT_LIST_HEAD(&d->slave.channels);
+ dma_cap_set(DMA_SLAVE, d->slave.cap_mask);
+ dma_cap_set(DMA_MEMCPY, d->slave.cap_mask);
+ d->slave.dev = &op->dev;
+ d->slave.device_alloc_chan_resources = k3_dma_alloc_chan_resources;
+ d->slave.device_free_chan_resources = k3_dma_free_chan_resources;
+ d->slave.device_tx_status = k3_dma_tx_status;
+ d->slave.device_prep_dma_memcpy = k3_dma_prep_memcpy;
+ d->slave.device_prep_slave_sg = k3_dma_prep_slave_sg;
+ d->slave.device_issue_pending = k3_dma_issue_pending;
+ d->slave.device_control = k3_dma_control;
+ d->slave.copy_align = DMA_ALIGN;
+ d->slave.chancnt = d->dma_requests;
+
+ /* init virtual channel */
+ d->chans = devm_kzalloc(&op->dev,
+ d->dma_requests * sizeof(struct k3_dma_chan), GFP_KERNEL);
+ if (d->chans == NULL)
+ return -ENOMEM;
+
+ for (i = 0; i < d->dma_requests; i++) {
+ struct k3_dma_chan *c = &d->chans[i];
+
+ c->status = DMA_IN_PROGRESS;
+ INIT_LIST_HEAD(&c->node);
+ c->vc.desc_free = k3_dma_free_desc;
+ vchan_init(&c->vc, &d->slave);
+ }
+
+ /* Enable clock before accessing registers */
+ ret = clk_prepare_enable(d->clk);
+ if (ret < 0) {
+ dev_err(&op->dev, "clk_prepare_enable failed: %d\n", ret);
+ return -EINVAL;
+ }
+
+ k3_dma_enable_dma(d, true);
+
+ ret = dma_async_device_register(&d->slave);
+ if (ret)
+ return ret;
+
+ ret = of_dma_controller_register((&op->dev)->of_node,
+ k3_of_dma_simple_xlate, d);
+ if (ret)
+ goto of_dma_register_fail;
+
+ spin_lock_init(&d->lock);
+ INIT_LIST_HEAD(&d->chan_pending);
+ tasklet_init(&d->task, k3_dma_tasklet, (unsigned long)d);
+ platform_set_drvdata(op, d);
+ dev_info(&op->dev, "initialized\n");
+
+ return 0;
+
+of_dma_register_fail:
+ dma_async_device_unregister(&d->slave);
+ return ret;
+}
+
+static int k3_dma_remove(struct platform_device *op)
+{
+ struct k3_dma_chan *c, *cn;
+ struct k3_dma_dev *d = platform_get_drvdata(op);
+
+ dma_async_device_unregister(&d->slave);
+ of_dma_controller_free((&op->dev)->of_node);
+
+ list_for_each_entry_safe(c, cn, &d->slave.channels, vc.chan.device_node) {
+ list_del(&c->vc.chan.device_node);
+ tasklet_kill(&c->vc.task);
+ }
+ tasklet_kill(&d->task);
+ clk_disable_unprepare(d->clk);
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int k3_dma_pltfm_suspend(struct device *dev)
+{
+ struct k3_dma_dev *d = dev_get_drvdata(dev);
+ u32 stat = 0;
+
+ stat = k3_dma_get_chan_stat(d);
+ if (stat) {
+ dev_warn(d->slave.dev,
+ "chan %d is running fail to suspend\n", stat);
+ return -1;
+ }
+ k3_dma_enable_dma(d, false);
+ clk_disable_unprepare(d->clk);
+ return 0;
+}
+
+static int k3_dma_pltfm_resume(struct device *dev)
+{
+ struct k3_dma_dev *d = dev_get_drvdata(dev);
+ int ret = 0;
+
+ ret = clk_prepare_enable(d->clk);
+ if (ret < 0) {
+ dev_err(d->slave.dev, "clk_prepare_enable failed: %d\n", ret);
+ return -EINVAL;
+ }
+ k3_dma_enable_dma(d, true);
+ return 0;
+}
+#else
+#define k3_dma_pltfm_suspend NULL
+#define k3_dma_pltfm_resume NULL
+#endif /* CONFIG_PM_SLEEP */
+
+SIMPLE_DEV_PM_OPS(k3_dma_pltfm_pmops, k3_dma_pltfm_suspend, k3_dma_pltfm_resume);
+
+static struct platform_driver k3_pdma_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .pm = &k3_dma_pltfm_pmops,
+ .of_match_table = k3_pdma_dt_ids,
+ },
+ .probe = k3_dma_probe,
+ .remove = k3_dma_remove,
+};
+
+module_platform_driver(k3_pdma_driver);
+
+MODULE_DESCRIPTION("Hisilicon k3 DMA Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c
index 4fbe12d283d5..207e41675241 100644
--- a/drivers/gpio/gpio-pl061.c
+++ b/drivers/gpio/gpio-pl061.c
@@ -256,6 +256,19 @@ static const struct irq_domain_ops pl061_domain_ops = {
.xlate = irq_domain_xlate_twocell,
};
+/* Parse gpio base from DT */
+static int pl061_parse_gpio_base(struct device *dev)
+{
+ struct device_node *np = dev->of_node;
+ int ret;
+
+ if (of_property_read_u32(np, "linux,gpio-base", &ret))
+ return -ENOENT;
+ if (ret >= 0)
+ return ret;
+ return -EINVAL;
+}
+
static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
{
struct device *dev = &adev->dev;
@@ -273,7 +286,7 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
if (irq_base <= 0)
return -ENODEV;
} else {
- chip->gc.base = -1;
+ chip->gc.base = pl061_parse_gpio_base(dev);
irq_base = 0;
}
@@ -288,8 +301,11 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
spin_lock_init(&chip->lock);
- chip->gc.request = pl061_gpio_request;
- chip->gc.free = pl061_gpio_free;
+ /* Hook the request()/free() for pinctrl operation */
+ if (of_get_property(dev->of_node, "gpio-ranges", NULL)) {
+ chip->gc.request = pl061_gpio_request;
+ chip->gc.free = pl061_gpio_free;
+ }
chip->gc.direction_input = pl061_direction_input;
chip->gc.direction_output = pl061_direction_output;
chip->gc.get = pl061_get_value;
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index c2534d62911c..ff0fd655729f 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1214,15 +1214,14 @@ int gpiochip_add(struct gpio_chip *chip)
}
}
+ spin_unlock_irqrestore(&gpio_lock, flags);
+
#ifdef CONFIG_PINCTRL
INIT_LIST_HEAD(&chip->pin_ranges);
#endif
of_gpiochip_add(chip);
-unlock:
- spin_unlock_irqrestore(&gpio_lock, flags);
-
if (status)
goto fail;
@@ -1235,6 +1234,9 @@ unlock:
chip->label ? : "generic");
return 0;
+
+unlock:
+ spin_unlock_irqrestore(&gpio_lock, flags);
fail:
/* failures here can mean systems won't boot... */
pr_err("gpiochip_add: gpios %d..%d (%s) failed to register\n",
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
index 35b70a1edf57..41659c0f25b7 100644
--- a/drivers/i2c/busses/i2c-designware-platdrv.c
+++ b/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -231,6 +231,7 @@ static SIMPLE_DEV_PM_OPS(dw_i2c_dev_pm_ops, dw_i2c_suspend, dw_i2c_resume);
MODULE_ALIAS("platform:i2c_designware");
static struct platform_driver dw_i2c_driver = {
+ .probe = dw_i2c_probe,
.remove = dw_i2c_remove,
.driver = {
.name = "i2c_designware",
@@ -240,18 +241,7 @@ static struct platform_driver dw_i2c_driver = {
.pm = &dw_i2c_dev_pm_ops,
},
};
-
-static int __init dw_i2c_init_driver(void)
-{
- return platform_driver_probe(&dw_i2c_driver, dw_i2c_probe);
-}
-subsys_initcall(dw_i2c_init_driver);
-
-static void __exit dw_i2c_exit_driver(void)
-{
- platform_driver_unregister(&dw_i2c_driver);
-}
-module_exit(dw_i2c_exit_driver);
+module_platform_driver(dw_i2c_driver);
MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
MODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter");
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 4abf046e30b1..c1116f14ad4f 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -93,6 +93,15 @@ config INPUT_BMA150
To compile this driver as a module, choose M here: the
module will be called bma150.
+config INPUT_HI6421_ONKEY
+ tristate "Hisilicon Hi6421 PMIC ONKEY support"
+ depends on MFD_HI6421_PMIC
+ help
+ Say Y to enable support for Hi6421 PMIC ONKEY.
+
+ To compile this driver as a module, choose M here: the
+ module will be called hi6421_pwrkey.
+
config INPUT_PCSPKR
tristate "PC Speaker support"
depends on PCSPKR_PLATFORM
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 6b0e8a677725..5978a0ce64f8 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_INPUT_DM355EVM) += dm355evm_keys.o
obj-$(CONFIG_INPUT_GP2A) += gp2ap002a00f.o
obj-$(CONFIG_INPUT_GPIO_TILT_POLLED) += gpio_tilt_polled.o
obj-$(CONFIG_INPUT_GPIO) += gpio_event.o gpio_matrix.o gpio_input.o gpio_output.o gpio_axis.o
+obj-$(CONFIG_INPUT_HI6421_ONKEY) += hi6421_pwrkey.o
obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o
obj-$(CONFIG_INPUT_IMS_PCU) += ims-pcu.o
obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o
diff --git a/drivers/input/misc/hi6421_pwrkey.c b/drivers/input/misc/hi6421_pwrkey.c
new file mode 100644
index 000000000000..31d0145fc688
--- /dev/null
+++ b/drivers/input/misc/hi6421_pwrkey.c
@@ -0,0 +1,153 @@
+/*
+ * hi6421_pwrkey.c - Hisilicon Hi6421 PMIC ONKEY driver
+ *
+ * Copyright (C) 2013 Hisilicon Ltd.
+ * Copyright (C) 2013 Linaro Ltd.
+ * Author: Haojian Zhuang <haojian.zhuang@linaro.org>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file "COPYING" in the main directory of this
+ * archive for more details.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/hi6421-pmic.h>
+
+struct hi6421_onkey_info {
+ struct input_dev *idev;
+ int irq[4];
+};
+
+static irqreturn_t hi6421_onkey_handler(int irq, void *data)
+{
+ struct hi6421_onkey_info *info = (struct hi6421_onkey_info *)data;
+
+ /* only handle power down & power up event at here */
+ if (irq == info->irq[0]) {
+ input_report_key(info->idev, KEY_POWER, 1);
+ input_sync(info->idev);
+ } else if (irq == info->irq[1]) {
+ input_report_key(info->idev, KEY_POWER, 0);
+ input_sync(info->idev);
+ }
+ return IRQ_HANDLED;
+}
+
+static int hi6421_onkey_probe(struct platform_device *pdev)
+{
+ struct hi6421_onkey_info *info;
+ struct device *dev = &pdev->dev;
+ int ret;
+
+ info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ info->idev = input_allocate_device();
+ if (!info->idev) {
+ dev_err(&pdev->dev, "Failed to allocate input device\n");
+ return -ENOMEM;
+ }
+ info->idev->name = "hi6421_on";
+ info->idev->phys = "hi6421_on/input0";
+ info->idev->dev.parent = &pdev->dev;
+ info->idev->evbit[0] = BIT_MASK(EV_KEY);
+ __set_bit(KEY_POWER, info->idev->keybit);
+
+ info->irq[0] = platform_get_irq_byname(pdev, "down");
+ if (info->irq[0] < 0) {
+ ret = -ENOENT;
+ goto err_irq0;
+ }
+ ret = request_irq(info->irq[0], hi6421_onkey_handler,
+ IRQF_DISABLED, "down", info);
+ if (ret < 0)
+ goto err_irq0;
+ info->irq[1] = platform_get_irq_byname(pdev, "up");
+ if (info->irq[1] < 0) {
+ ret = -ENOENT;
+ goto err_irq1;
+ }
+ ret = request_irq(info->irq[1], hi6421_onkey_handler,
+ IRQF_DISABLED, "up", info);
+ if (ret < 0)
+ goto err_irq1;
+ info->irq[2] = platform_get_irq_byname(pdev, "hold 1s");
+ if (info->irq[2] < 0) {
+ ret = -ENOENT;
+ goto err_irq2;
+ }
+ ret = request_irq(info->irq[2], hi6421_onkey_handler,
+ IRQF_DISABLED, "hold 1s", info);
+ if (ret < 0)
+ goto err_irq2;
+ info->irq[3] = platform_get_irq_byname(pdev, "hold 10s");
+ if (info->irq[3] < 0) {
+ ret = -ENOENT;
+ goto err_irq3;
+ }
+ ret = request_irq(info->irq[3], hi6421_onkey_handler,
+ IRQF_DISABLED, "hold 10s", info);
+ if (ret < 0)
+ goto err_irq3;
+
+ ret = input_register_device(info->idev);
+ if (ret) {
+ dev_err(&pdev->dev, "Can't register input device: %d\n", ret);
+ goto err_reg;
+ }
+
+ platform_set_drvdata(pdev, info);
+ return ret;
+err_reg:
+ free_irq(info->irq[3], info);
+err_irq3:
+ free_irq(info->irq[2], info);
+err_irq2:
+ free_irq(info->irq[1], info);
+err_irq1:
+ free_irq(info->irq[0], info);
+err_irq0:
+ input_free_device(info->idev);
+ return ret;
+}
+
+static int hi6421_onkey_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static struct of_device_id hi6421_onkey_of_match[] = {
+ { .compatible = "hisilicon,hi6421-onkey", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, hi6421_onkey_of_match);
+
+static struct platform_driver hi6421_onkey_driver = {
+ .probe = hi6421_onkey_probe,
+ .remove = hi6421_onkey_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "hi6421-onkey",
+ .of_match_table = hi6421_onkey_of_match,
+ },
+};
+module_platform_driver(hi6421_onkey_driver);
+
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@linaro.org");
+MODULE_DESCRIPTION("Hi6421 PMIC Power key driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index f9a5fd89bc02..dee8f0e0ec68 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -888,4 +888,16 @@ config TOUCHSCREEN_TPS6507X
To compile this driver as a module, choose M here: the
module will be called tps6507x_ts.
+config TOUCHSCREEN_MXT224E
+ tristate "Atmel mXT224E based touchscreens"
+ depends on I2C
+ help
+ Say Y here if you have a TPS6507x based touchscreen
+ controller.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called atmel_mXT224E.
+
endif
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 6bfbeab67c9f..a00b61bcb740 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -72,3 +72,4 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o
obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o
obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o
obj-$(CONFIG_TOUCHSCREEN_TPS6507X) += tps6507x-ts.o
+obj-$(CONFIG_TOUCHSCREEN_MXT224E) += atmel_mXT224E.o
diff --git a/drivers/input/touchscreen/atmel_mXT224E.c b/drivers/input/touchscreen/atmel_mXT224E.c
new file mode 100644
index 000000000000..0a7fab242d98
--- /dev/null
+++ b/drivers/input/touchscreen/atmel_mXT224E.c
@@ -0,0 +1,1473 @@
+/* drivers/input/touchscreen/atmel_mXT224E.c - ATMEL Touch driver
+ *
+ * Copyright (C) 2008 ATMEL
+ * Copyright (C) 2011 Huawei Corporation.
+ *
+ * Based on touchscreen code from Atmel Corporation.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/jiffies.h>
+#include <linux/stat.h>
+#include <linux/slab.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/bitops.h>
+#include <linux/of_gpio.h>
+#include <linux/pinctrl/consumer.h>
+
+#include <linux/kthread.h>
+
+#ifdef TS_ATMEL_DEBUG
+#define TS_DEBUG_ATMEL(fmt, args...) pr_info(fmt, ##args)
+#else
+#define TS_DEBUG_ATMEL(fmt, args...)
+#endif
+
+#define ATMEL_MXT224E_NAME "atmel_mxt224e"
+
+#define INFO_BLK_FID 0
+#define INFO_BLK_VID 1
+#define INFO_BLK_VER 2
+#define INFO_BLK_BUILD 3
+#define INFO_BLK_XSIZE 4
+#define INFO_BLK_YSIZE 5
+#define INFO_BLK_OBJS 6
+
+#define OBJ_TABLE_TYPE 0
+#define OBJ_TABLE_LSB 1
+#define OBJ_TABLE_MSB 2
+#define OBJ_TABLE_SIZE 3
+#define OBJ_TABLE_INSTANCES 4
+#define OBJ_TABLE_RIDS 5
+
+#define RESERVED_T0 0u
+#define RESERVED_T1 1u
+#define DEBUG_DELTAS_T2 2u
+#define DEBUG_REFERENCES_T3 3u
+#define DEBUG_SIGNALS_T4 4u
+#define GEN_MESSAGEPROCESSOR_T5 5u
+#define GEN_COMMANDPROCESSOR_T6 6u
+#define GEN_POWERCONFIG_T7 7u
+#define GEN_ACQUISITIONCONFIG_T8 8u
+#define TOUCH_MULTITOUCHSCREEN_T9 9u
+#define TOUCH_SINGLETOUCHSCREEN_T10 10u
+#define TOUCH_XSLIDER_T11 11u
+#define TOUCH_YSLIDER_T12 12u
+#define TOUCH_XWHEEL_T13 13u
+#define TOUCH_YWHEEL_T14 14u
+#define TOUCH_KEYARRAY_T15 15u
+#define PROCG_SIGNALFILTER_T16 16u
+#define PROCI_LINEARIZATIONTABLE_T17 17u
+#define SPT_COMCONFIG_T18 18u
+#define SPT_GPIOPWM_T19 19u
+#define PROCI_GRIPFACESUPPRESSION_T20 20u
+#define RESERVED_T21 21u
+#define PROCG_NOISESUPPRESSION_T22 22u
+#define TOUCH_PROXIMITY_T23 23u
+#define PROCI_ONETOUCHGESTUREPROCESSOR_T24 24u
+#define SPT_SELFTEST_T25 25u
+#define DEBUG_CTERANGE_T26 26u
+#define PROCI_TWOTOUCHGESTUREPROCESSOR_T27 27u
+#define SPT_CTECONFIG_T28 28u
+#define SPT_GPI_T29 29u
+#define SPT_GATE_T30 30u
+#define TOUCH_KEYSET_T31 31u
+#define TOUCH_XSLIDERSET_T32 32u
+#define DIAGNOSTIC_T37 37u
+#define PROCI_GRIPSUPPRESSION_T40 40u
+#define PROCI_TOUCHSUPPRESSION_T42 42u
+#define SPT_CTECONFIG_T46 46u
+#define PROCI_STYLUS_T47 47u
+#define PROCG_NOISESUPPRESSION_T48 48u
+
+#define T37_PAGE_SIZE 128
+
+#define T37_TCH_FLAG_SIZE 80
+#define T37_TCH_FLAG_IDX 0
+#define T37_ATCH_FLAG_IDX 40
+
+#define T37_MODE 0
+#define T37_PAGE 1
+#define T37_DATA 2 /* n bytes */
+
+#define T37_PAGE_NUM0 0
+#define T37_PAGE_NUM1 1
+#define T37_PAGE_NUM2 2
+#define T37_PAGE_NUM3 3
+
+#define MSG_RID 0
+
+#define T6_CFG_RESET 0
+#define T6_CFG_BACKUPNV 1
+#define T6_CFG_CALIBRATE 2
+#define T6_CFG_REPORTALL 3
+/* Reserved */
+#define T6_CFG_DIAG 5
+
+#define T6_CFG_DIAG_CMD_PAGEUP 0x01
+#define T6_CFG_DIAG_CMD_PAGEDOWN 0x02
+#define T6_CFG_DIAG_CMD_DELTAS 0x10
+#define T6_CFG_DIAG_CMD_REF 0x11
+#define T6_CFG_DIAG_CMD_CTE 0x31
+#define T6_CFG_DIAG_CMD_TCH 0xF3
+
+#define T6_MSG_STATUS 1
+#define T6_MSG_CHECKSUM 2 /* three bytes */
+
+#define T6_MSG_STATUS_COMSERR BIT(2)
+#define T6_MSG_STATUS_CFGERR BIT(3)
+#define T6_MSG_STATUS_CAL BIT(4)
+#define T6_MSG_STATUS_SIGERR BIT(5)
+#define T6_MSG_STATUS_OFL BIT(6)
+#define T6_MSG_STATUS_RESET BIT(7)
+
+#define T7_CFG_IDLEACQINT 0
+#define T7_CFG_ACTVACQINT 1
+#define T7_CFG_ACTV2IDLETO 2
+
+#define T8_CFG_CHRGTIME 0
+/* Reserved */
+#define T8_CFG_TCHDRIFT 2
+#define T8_CFG_DRIFTST 3
+#define T8_CFG_TCHAUTOCAL 4
+#define T8_CFG_SYNC 5
+#define T8_CFG_ATCHCALST 6
+#define T8_CFG_ATCHCALSTHR 7
+#define T8_CFG_ATCHFRCCALTHR 8 /* FW v2.x */
+#define T8_CFG_ATCHFRCCALRATIO 9 /* FW v2.x */
+
+#define T9_CFG_CTRL 0
+#define T9_CFG_XORIGIN 1
+#define T9_CFG_YORIGIN 2
+#define T9_CFG_XSIZE 3
+#define T9_CFG_YSIZE 4
+#define T9_CFG_AKSCFG 5
+#define T9_CFG_BLEN 6
+#define T9_CFG_TCHTHR 7
+#define T9_CFG_TCHDI 8
+#define T9_CFG_ORIENT 9
+#define T9_CFG_MRGTIMEOUT 10
+#define T9_CFG_MOVHYSTI 11
+#define T9_CFG_MOVHYSTN 12
+#define T9_CFG_MOVFILTER 13
+#define T9_CFG_NUMTOUCH 14
+#define T9_CFG_MRGHYST 15
+#define T9_CFG_MRGTHR 16
+#define T9_CFG_AMPHYST 17
+#define T9_CFG_XRANGE 18 /* two bytes */
+#define T9_CFG_YRANGE 20 /* two bytes */
+#define T9_CFG_XLOCLIP 22
+#define T9_CFG_XHICLIP 23
+#define T9_CFG_YLOCLIP 24
+#define T9_CFG_YHICLIP 25
+#define T9_CFG_XEDGECTRL 26
+#define T9_CFG_XEDGEDIST 27
+#define T9_CFG_YEDGECTRL 28
+#define T9_CFG_YEDGEDIST 29
+#define T9_CFG_JUMPLIMIT 30
+#define T9_CFG_TCHHYST 31 /* FW v2.x */
+
+#define T9_MSG_STATUS 1
+#define T9_MSG_XPOSMSB 2
+#define T9_MSG_YPOSMSB 3
+#define T9_MSG_XYPOSLSB 4
+#define T9_MSG_TCHAREA 5
+#define T9_MSG_TCHAMPLITUDE 6
+#define T9_MSG_TCHVECTOR 7
+
+#define T9_MSG_STATUS_UNGRIP BIT(0) /* FW v2.x */
+#define T9_MSG_STATUS_SUPPRESS BIT(1)
+#define T9_MSG_STATUS_AMP BIT(2)
+#define T9_MSG_STATUS_VECTOR BIT(3)
+#define T9_MSG_STATUS_MOVE BIT(4)
+#define T9_MSG_STATUS_RELEASE BIT(5)
+#define T9_MSG_STATUS_PRESS BIT(6)
+#define T9_MSG_STATUS_DETECT BIT(7)
+
+#define T20_CFG_CTRL 0
+#define T20_CFG_XLOGRIP 1
+#define T20_CFG_XHIGRIP 2
+#define T20_CFG_YLOGRIP 3
+#define T20_CFG_YHIGRIP 4
+#define T20_CFG_MAXTCHS 5
+/* Reserved */
+#define T20_CFG_SZTHR1 7
+#define T20_CFG_SZTHR2 8
+#define T20_CFG_SHPTHR1 9
+#define T20_CFG_SHPTHR2 10
+#define T20_CFG_SHPEXTTO 11
+
+#define T20_MSG_STATUS 1
+
+#define T20_MSG_STATUS_FACESUP BIT(0)
+
+#define T22_CFG_CTRL 0
+/* Reserved */
+#define T22_CFG_GCAFUL 3 /* two bytes */
+#define T22_CFG_GCAFLL 5 /* two bytes */
+#define T22_CFG_ACTVGCAFVALID 7
+#define T22_CFG_NOISETHR 8
+/* Reserved */
+#define T22_CFG_FREQHOPSCALE 10
+#define T22_CFG_FREQ 11 /* five bytes */
+#define T22_CFG_IDLEGCAFVAILD 16
+
+#define T22_MSG_STATUS 1
+#define T22_MSG_GCAFDEPTH 2
+#define T22_MSG_FREQINDEX 3
+
+#define T22_MSG_STATUS_FHCHG BIT(0)
+#define T22_MSG_STATUS_GCAFERR BIT(2)
+#define T22_MSG_STATUS_FHERR BIT(3)
+#define T22_MSG_STATUS_GCAFCHG BIT(4)
+
+#define T19_CFG_CTRL 0
+#define T19_CFG_REPORTMASK 1
+#define T19_CFG_DIR 2
+#define T19_CFG_INTPULLUP 3
+#define T19_CFG_OUT 4
+#define T19_CFG_WAKE 5
+#define T19_CFG_PWM 6
+#define T19_CFG_PERIOD 7
+#define T19_CFG_DUTY0 8
+#define T19_CFG_DUTY1 9
+#define T19_CFG_DUTY2 10
+#define T19_CFG_DUTY3 11
+#define T19_CFG_TRIGGER0 12
+#define T19_CFG_TRIGGER1 13
+#define T19_CFG_TRIGGER2 14
+#define T19_CFG_TRIGGER3 15
+
+#define T19_CFG_CTRL_ENABLE BIT(0)
+#define T19_CFG_CTRL_RPTEN BIT(1)
+#define T19_CFG_CTRL_FORCERPT BIT(2)
+
+#define T19_MSG_STATUS 1
+
+#define T25_CFG_CTRL 0
+#define T25_CFG_CMD 1
+
+#define T25_MSG_STATUS 1
+#define T25_MSG_INFO 2 /* five bytes */
+
+#define T28_CFG_CTRL 0
+#define T28_CFG_CMD 1
+#define T28_CFG_MODE 2
+#define T28_CFG_IDLEGCAFDEPTH 3
+#define T28_CFG_ACTVGCAFDEPTH 4
+#define T28_CFG_VOLTAGE 5
+
+#define T28_CFG_MODE0_X 16
+#define T28_CFG_MODE0_Y 14
+
+#define T28_MSG_STATUS 1
+
+#define T48_NOISESUPPRESSION_CFG 1
+
+/* cable_config[] of atmel_i2c_platform_data */
+/* config[] of atmel_config_data */
+#define CB_TCHTHR 0
+#define CB_NOISETHR 1
+#define CB_IDLEGCAFDEPTH 2
+#define CB_ACTVGCAFDEPTH 3
+
+#define NC_TCHTHR 0
+#define NC_TCHDI 1
+#define NC_NOISETHR 2
+
+/* filter_level */
+#define FL_XLOGRIPMIN 0
+#define FL_XLOGRIPMAX 1
+#define FL_XHIGRIPMIN 2
+#define FL_XHIGRIPMAX 3
+
+struct info_id_t {
+ uint8_t family_id;
+ uint8_t variant_id;
+ uint8_t version;
+ uint8_t build;
+ uint8_t matrix_x_size;
+ uint8_t matrix_y_size;
+ uint8_t num_declared_objects;
+};
+
+struct object_t {
+ uint8_t object_type;
+ uint16_t i2c_address;
+ uint8_t size;
+ uint8_t instances;
+ uint8_t num_report_ids;
+ uint8_t report_ids;
+};
+
+struct atmel_virtual_key {
+ int keycode;
+ int range_min;
+ int range_max;
+};
+
+struct atmel_finger_data {
+ int x;
+ int y;
+ int w;
+ int z;
+};
+
+struct atmel_i2c_platform_data {
+ uint16_t version;
+ uint16_t source;
+ uint16_t abs_x_min;
+ uint16_t abs_x_max;
+ uint16_t abs_y_min;
+ uint16_t abs_y_max;
+ uint8_t abs_pressure_min;
+ uint8_t abs_pressure_max;
+ uint8_t abs_width_min;
+ uint8_t abs_width_max;
+ uint8_t abs_area_min;
+ uint8_t abs_area_max;
+ int gpio_irq;
+ int gpio_reset;
+ int (*power)(int on);
+ u8 config_T6[6];
+ u8 config_T7[3];
+ u8 config_T8[10];
+ u8 config_T9[35];
+ u8 config_T15[11];
+ u8 config_T19[16];
+ u8 config_T20[12];
+ u8 config_T22[17];
+ u8 config_T23[15];
+ u8 config_T24[19];
+ u8 config_T25[14];
+ u8 config_T27[7];
+ u8 config_T28[6];
+ u8 config_T40[5];
+ u8 config_T42[8];
+ u8 config_T46[9];
+ u8 config_T47[10];
+ u8 config_T48[54];
+ u8 object_crc[3];
+ u8 cable_config[4];
+ u8 cable_config_T7[3];
+ u8 cable_config_T8[10];
+ u8 cable_config_T9[35];
+ u8 cable_config_T22[17];
+ u8 cable_config_T28[6];
+ u8 cable_config_T46[9];
+ u8 cable_config_T48[54];
+ u8 noise_config[3];
+ u16 filter_level[4];
+ u8 GCAF_level[5];
+ u8 ATCH_NOR[6];
+ u8 ATCH_NOR_20S[6];
+};
+
+struct atmel_config_data {
+ int8_t config[4];
+ int8_t *config_T7;
+ int8_t *config_T8;
+ int8_t *config_T9;
+ int8_t *config_T22;
+ int8_t *config_T28;
+ int8_t *config_T46;
+ int8_t *config_T48;
+};
+
+#define ATMEL_I2C_RETRY_TIMES 10
+
+/* config_setting */
+#define NONE 0
+#define CONNECTED 1
+struct atmel_ts_data {
+ struct i2c_client *client;
+ struct input_dev *input_dev;
+ struct atmel_i2c_platform_data *pdata;
+ struct workqueue_struct *atmel_wq;
+ struct work_struct work;
+ int (*power) (int on);
+ struct info_id_t *id;
+ struct object_t *object_table;
+ struct iomux_block *gpio_block;
+ struct block_config *gpio_block_config;
+ uint8_t finger_count;
+ uint16_t abs_x_min;
+ uint16_t abs_x_max;
+ uint16_t abs_y_min;
+ uint16_t abs_y_max;
+ uint8_t abs_area_min;
+ uint8_t abs_area_max;
+ uint8_t abs_width_min;
+ uint8_t abs_width_max;
+ uint8_t abs_pressure_min;
+ uint8_t abs_pressure_max;
+ uint8_t first_pressed;
+ struct atmel_finger_data finger_data[10];
+ uint8_t finger_type;
+ uint8_t finger_support;
+ uint16_t finger_pressed;
+ uint8_t face_suppression;
+ uint8_t grip_suppression;
+ uint8_t noise_status[2];
+ uint16_t *filter_level;
+ uint8_t calibration_confirm;
+ uint64_t timestamp;
+ struct atmel_config_data config_setting[2];
+ int8_t noise_config[3];
+ uint8_t status;
+ uint8_t GCAF_sample;
+ uint8_t *GCAF_level;
+ uint8_t noisethr;
+ uint8_t noisethr_config;
+ uint8_t diag_command;
+ uint8_t *ATCH_EXT;
+ int8_t *ATCH_NOR;
+ int8_t *ATCH_NOR_20S;
+ int pre_data[11];
+ /*unlock flag used to indicate calibration after unlock system*/
+ int unlock_flag;
+
+ /*For usb detect*/
+ struct work_struct usb_work;
+ struct notifier_block nb;
+ unsigned long usb_event;
+ struct mutex lock;
+};
+
+static struct atmel_ts_data *private_ts;
+
+#define LDO_POWR_VOLTAGE 2700000 /*2.7v*/
+static struct regulator *LDO;
+
+int i2c_atmel_read(struct i2c_client *client, uint16_t address, uint8_t *data, uint8_t length)
+{
+ int retry, ret;
+ uint8_t addr[2];
+
+ struct i2c_msg msg[] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .len = 2,
+ .buf = addr,
+ },
+ {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = length,
+ .buf = data,
+ }
+ };
+ addr[0] = address & 0xFF;
+ addr[1] = (address >> 8) & 0xFF;
+
+ for (retry = 0; retry < ATMEL_I2C_RETRY_TIMES; retry++) {
+ ret = i2c_transfer(client->adapter, msg, 2);
+ if ((ret == 2) || (ret == -ERESTARTSYS))
+ break;
+ mdelay(10);
+ }
+ if (retry == ATMEL_I2C_RETRY_TIMES) {
+ dev_err(&client->dev, "k3ts, %s: i2c_read_block retry over %d\n", __func__,
+ ATMEL_I2C_RETRY_TIMES);
+ return -EIO;
+ }
+ return 0;
+}
+
+int i2c_atmel_write(struct i2c_client *client, uint16_t address, uint8_t *data, uint8_t length)
+{
+ int retry, loop_i, ret;
+ uint8_t buf[length + 2];
+
+ struct i2c_msg msg[] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .len = length + 2,
+ .buf = buf,
+ }
+ };
+
+ buf[0] = address & 0xFF;
+ buf[1] = (address >> 8) & 0xFF;
+
+ for (loop_i = 0; loop_i < length; loop_i++)
+ buf[loop_i + 2] = data[loop_i];
+
+ for (retry = 0; retry < ATMEL_I2C_RETRY_TIMES; retry++) {
+ ret = i2c_transfer(client->adapter, msg, 1);
+ if ((ret == 1) || (ret == -ERESTARTSYS))
+ break;
+ mdelay(10);
+ }
+
+ if (retry == ATMEL_I2C_RETRY_TIMES) {
+ dev_err(&client->dev, "k3ts, %s: i2c_write_block retry over %d\n", __func__,
+ ATMEL_I2C_RETRY_TIMES);
+ return -EIO;
+ }
+ return 0;
+
+}
+
+int i2c_atmel_write_byte_data(struct i2c_client *client, uint16_t address, uint8_t value)
+{
+ i2c_atmel_write(client, address, &value, 1);
+ return 0;
+}
+
+uint16_t get_object_address(struct atmel_ts_data *ts, uint8_t object_type)
+{
+ uint8_t loop_i;
+ for (loop_i = 0; loop_i < ts->id->num_declared_objects; loop_i++) {
+ if (ts->object_table[loop_i].object_type == object_type)
+ return ts->object_table[loop_i].i2c_address;
+ }
+ return 0;
+}
+uint8_t get_object_size(struct atmel_ts_data *ts, uint8_t object_type)
+{
+ uint8_t loop_i;
+ for (loop_i = 0; loop_i < ts->id->num_declared_objects; loop_i++) {
+ if (ts->object_table[loop_i].object_type == object_type)
+ return ts->object_table[loop_i].size;
+ }
+ return 0;
+}
+
+uint8_t get_object_size_from_address(struct atmel_ts_data *ts, int address)
+{
+ uint8_t loop_i;
+ for (loop_i = 0; loop_i < ts->id->num_declared_objects; loop_i++) {
+ if (ts->object_table[loop_i].i2c_address == address)
+ return ts->object_table[loop_i].size;
+ }
+ return 0;
+}
+
+uint8_t get_rid(struct atmel_ts_data *ts, uint8_t object_type)
+{
+ uint8_t loop_i;
+ for (loop_i = 0; loop_i < ts->id->num_declared_objects; loop_i++) {
+ if (ts->object_table[loop_i].object_type == object_type)
+ return ts->object_table[loop_i].report_ids;
+ }
+ return 0;
+}
+
+static void check_calibration(struct atmel_ts_data *ts)
+{
+ uint8_t data[T37_DATA + T37_TCH_FLAG_SIZE];
+ uint8_t loop_i, loop_j, x_limit = 0, check_mask, tch_ch = 0, atch_ch = 0;
+
+ memset(data, 0xFF, sizeof(data));
+ i2c_atmel_write_byte_data(ts->client,
+ get_object_address(ts, GEN_COMMANDPROCESSOR_T6) +
+ T6_CFG_DIAG, T6_CFG_DIAG_CMD_TCH);
+
+ for (loop_i = 0;
+ !(data[T37_MODE] == T6_CFG_DIAG_CMD_TCH && data[T37_PAGE] == T37_PAGE_NUM0) && loop_i < 10; loop_i++) {
+ msleep(5);
+ i2c_atmel_read(ts->client,
+ get_object_address(ts, DIAGNOSTIC_T37), data, 2);
+ }
+
+ if (loop_i == 10)
+ dev_err(&ts->client->dev, "k3ts, %s: Diag data not ready\n", __func__);
+
+ i2c_atmel_read(ts->client, get_object_address(ts, DIAGNOSTIC_T37), data,
+ T37_DATA + T37_TCH_FLAG_SIZE);
+ if (data[T37_MODE] == T6_CFG_DIAG_CMD_TCH &&
+ data[T37_PAGE] == T37_PAGE_NUM0) {
+ x_limit = T28_CFG_MODE0_X + ts->config_setting[NONE].config_T28[T28_CFG_MODE];
+ x_limit = x_limit << 1;
+ if (x_limit <= 40) {
+ for (loop_i = 0; loop_i < x_limit; loop_i += 2) {
+ for (loop_j = 0; loop_j < BITS_PER_BYTE; loop_j++) {
+ check_mask = BIT_MASK(loop_j);
+ if (data[T37_DATA + T37_TCH_FLAG_IDX + loop_i] &
+ check_mask)
+ tch_ch++;
+ if (data[T37_DATA + T37_TCH_FLAG_IDX + loop_i + 1] &
+ check_mask)
+ tch_ch++;
+ if (data[T37_DATA + T37_ATCH_FLAG_IDX + loop_i] &
+ check_mask)
+ atch_ch++;
+ if (data[T37_DATA + T37_ATCH_FLAG_IDX + loop_i + 1] &
+ check_mask)
+ atch_ch++;
+ }
+ }
+ }
+ }
+ i2c_atmel_write_byte_data(ts->client,
+ get_object_address(ts, GEN_COMMANDPROCESSOR_T6) +
+ T6_CFG_DIAG, T6_CFG_DIAG_CMD_PAGEUP);
+
+ if (tch_ch && (atch_ch == 0)) {
+ if (jiffies > (ts->timestamp + HZ/2) && (ts->calibration_confirm == 1)) {
+ ts->calibration_confirm = 2;
+ }
+ if (ts->calibration_confirm < 2)
+ ts->calibration_confirm = 1;
+ ts->timestamp = jiffies;
+ } else if (atch_ch > 1 || tch_ch > 8) {
+ ts->calibration_confirm = 0;
+ i2c_atmel_write_byte_data(ts->client,
+ get_object_address(ts, GEN_COMMANDPROCESSOR_T6) +
+ T6_CFG_CALIBRATE, 0x55);
+ }
+}
+
+static void confirm_calibration(struct atmel_ts_data *ts)
+{
+ i2c_atmel_write(ts->client,
+ get_object_address(ts, GEN_ACQUISITIONCONFIG_T8) +
+ T8_CFG_TCHAUTOCAL, ts->ATCH_NOR_20S, 6);
+ ts->pre_data[0] = 2;
+}
+
+static void msg_process_finger_data_x10y10bit(struct atmel_finger_data *fdata, uint8_t *data)
+{
+ fdata->x = data[T9_MSG_XPOSMSB] << 2 | data[T9_MSG_XYPOSLSB] >> 6;
+ fdata->y = data[T9_MSG_YPOSMSB] << 2 | (data[T9_MSG_XYPOSLSB] & 0x0C) >>2;
+ fdata->w = data[T9_MSG_TCHAREA];
+ fdata->z = data[T9_MSG_TCHAMPLITUDE];
+}
+static void msg_process_finger_data_x10y12bit(struct atmel_finger_data *fdata, uint8_t *data)
+{
+ fdata->x = data[T9_MSG_XPOSMSB] << 2 | data[T9_MSG_XYPOSLSB] >> 6;
+ fdata->y = data[T9_MSG_YPOSMSB] << 4 | (data[T9_MSG_XYPOSLSB] & 0x0F) ;
+ fdata->w = data[T9_MSG_TCHAREA];
+ fdata->z = data[T9_MSG_TCHAMPLITUDE];
+}
+
+static void msg_process_multitouch(struct atmel_ts_data *ts, uint8_t *data, uint8_t idx)
+{
+ if (ts->calibration_confirm < 2 && ts->id->version == 0x10)
+ check_calibration(ts);
+ if(ts->abs_y_max >= 1024) {
+ msg_process_finger_data_x10y12bit(&ts->finger_data[idx], data);
+ } else {
+ msg_process_finger_data_x10y10bit(&ts->finger_data[idx], data);
+ }
+ if (data[T9_MSG_STATUS] & T9_MSG_STATUS_RELEASE) {
+ if (ts->grip_suppression & BIT(idx))
+ ts->grip_suppression &= ~BIT(idx);
+ if (ts->finger_pressed & BIT(idx)) {
+ ts->finger_count--;
+ ts->finger_pressed &= ~BIT(idx);
+ if (!ts->first_pressed) {
+ if (!ts->finger_count)
+ ts->first_pressed = 1;
+ }
+ if (ts->pre_data[0] < 2 && ts->unlock_flag != 1) {
+
+ if (ts->finger_count) {
+ i2c_atmel_write_byte_data(ts->client,
+ get_object_address(ts, GEN_COMMANDPROCESSOR_T6) +
+ T6_CFG_CALIBRATE, 0x55);
+ } else if (!ts->finger_count && ts->pre_data[0] == 1)
+ ts->pre_data[0] = 0;
+ }
+ }
+ } else if ((data[T9_MSG_STATUS] & (T9_MSG_STATUS_DETECT | T9_MSG_STATUS_PRESS))
+ && !(ts->finger_pressed & BIT(idx))) {
+ if (ts->id->version >= 0x10 && ts->pre_data[0] < 2) {
+ if (jiffies > (ts->timestamp + 20 * HZ)) {
+ confirm_calibration(ts);
+ }
+ }
+ if (!(ts->grip_suppression & BIT(idx))) {
+ ts->finger_count++;
+ ts->finger_pressed |= BIT(idx);
+ if (ts->id->version >= 0x10 && ts->pre_data[0] < 2) {
+ ts->pre_data[idx + 1] = ts->finger_data[idx].x;
+ ts->pre_data[idx + 2] = ts->finger_data[idx].y;
+ if (ts->finger_count == ts->finger_support) {
+ i2c_atmel_write_byte_data(ts->client,
+ get_object_address(ts, GEN_COMMANDPROCESSOR_T6) +
+ T6_CFG_CALIBRATE, 0x55);
+ } else if (!ts->pre_data[0] && ts->finger_count == 1)
+ ts->pre_data[0] = 1;
+ }
+ }
+ } else if ((data[T9_MSG_STATUS] & (T9_MSG_STATUS_DETECT|T9_MSG_STATUS_PRESS))
+ && ts->pre_data[0] < 2 && ts->unlock_flag != 1) {
+ if (ts->finger_count == 1 && ts->pre_data[0] &&
+ (idx == 0 && ((abs(ts->finger_data[idx].y - ts->pre_data[idx + 2]) > 50)
+ || (abs(ts->finger_data[idx].x - ts->pre_data[idx + 1]) > 50))))
+ {
+ ts->unlock_flag = 1;
+ ts->calibration_confirm = 2;
+ }
+ }
+
+}
+
+static void compatible_input_report(struct input_dev *idev,
+ struct atmel_finger_data *fdata, uint8_t press, uint8_t last)
+{
+ if (!press) {
+ input_mt_sync(idev);
+ /*input_report_key(idev, BTN_TOUCH, 0);*/
+ input_report_key(idev, BTN_TOUCH, 1);
+
+ } else {
+ TS_DEBUG_ATMEL("k3ts, %s: Touch report_key x = %d, y = %d, z = %d, w = %d\n ", __func__,
+ fdata->x, fdata->y, fdata->z, fdata->w);
+ input_report_abs(idev, ABS_MT_TOUCH_MAJOR, fdata->z);
+ input_report_abs(idev, ABS_MT_WIDTH_MAJOR, fdata->w);
+ input_report_abs(idev, ABS_MT_POSITION_X, fdata->x);
+ input_report_abs(idev, ABS_MT_POSITION_Y, fdata->y);
+ input_mt_sync(idev);
+ }
+}
+
+
+
+static void multi_input_report(struct atmel_ts_data *ts)
+{
+ uint8_t loop_i, finger_report = 0;
+
+ for (loop_i = 0; loop_i < ts->finger_support; loop_i++) {
+ if (ts->finger_pressed & BIT(loop_i)) {
+ compatible_input_report(ts->input_dev, &ts->finger_data[loop_i],
+ 1, (ts->finger_count == ++finger_report));
+ }
+ }
+}
+static irqreturn_t atmel_interrupt_fun(int irq, void *dev_id)
+{
+ int ret;
+ struct atmel_ts_data *ts = dev_id;
+ uint8_t data[7];
+ int8_t report_type;
+ uint8_t msg_byte_num = 7;
+
+ memset(data, 0x0, sizeof(data));
+
+ mutex_lock(&ts->lock);
+ ret = i2c_atmel_read(ts->client, get_object_address(ts,
+ GEN_MESSAGEPROCESSOR_T5), data, 7);
+
+ report_type = data[MSG_RID] - ts->finger_type;
+ if (report_type >= 0 && report_type < ts->finger_support) {
+ msg_process_multitouch(ts, data, report_type);
+ } else {
+ if (data[MSG_RID] == get_rid(ts, GEN_COMMANDPROCESSOR_T6)) {
+ if (data[1] & 0x10) {
+ ts->timestamp = jiffies;
+ }
+ if (data[1] & 0x80) {
+ msleep(100);
+
+ i2c_atmel_write_byte_data(ts->client,
+ get_object_address(ts, GEN_COMMANDPROCESSOR_T6) +
+ T6_CFG_CALIBRATE, 0x55);
+ }
+ msg_byte_num = 5;
+ }
+ if (data[MSG_RID] == get_rid(ts, PROCI_TOUCHSUPPRESSION_T42)) {
+ if (ts->calibration_confirm < 2 && ts->id->version == 0x10) {
+ i2c_atmel_write_byte_data(ts->client,
+ get_object_address(ts, GEN_COMMANDPROCESSOR_T6) +
+ T6_CFG_CALIBRATE, 0x55);
+ }
+ ts->face_suppression = data[T20_MSG_STATUS];
+ printk(KERN_INFO "Touch Face suppression %s: ",
+ ts->face_suppression ? "Active" : "Inactive");
+ msg_byte_num = 2;
+ }
+ }
+ if (!ts->finger_count || ts->face_suppression) {
+ ts->finger_pressed = 0;
+ ts->finger_count = 0;
+ compatible_input_report(ts->input_dev, NULL, 0, 1);
+ } else {
+ multi_input_report(ts);
+ }
+ input_sync(ts->input_dev);
+ mutex_unlock(&ts->lock);
+
+ return IRQ_HANDLED;
+}
+
+static int read_object_table(struct atmel_ts_data *ts)
+{
+ uint8_t i, type_count = 0;
+ uint8_t data[6];
+ memset(data, 0x0, sizeof(data));
+
+ ts->object_table = kzalloc(sizeof(struct object_t)*ts->id->num_declared_objects, GFP_KERNEL);
+ if (ts->object_table == NULL) {
+ dev_err(&ts->client->dev, "k3ts, %s: allocate object_table failed\n", __func__);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < ts->id->num_declared_objects; i++) {
+ i2c_atmel_read(ts->client, i * 6 + 0x07, data, 6);
+ ts->object_table[i].object_type = data[OBJ_TABLE_TYPE];
+ ts->object_table[i].i2c_address =
+ data[OBJ_TABLE_LSB] | data[OBJ_TABLE_MSB] << 8;
+ ts->object_table[i].size = data[OBJ_TABLE_SIZE] + 1;
+ ts->object_table[i].instances = data[OBJ_TABLE_INSTANCES];
+ ts->object_table[i].num_report_ids = data[OBJ_TABLE_RIDS];
+ if (data[OBJ_TABLE_RIDS]) {
+ ts->object_table[i].report_ids = type_count + 1;
+ type_count += data[OBJ_TABLE_RIDS];
+ }
+ if (data[OBJ_TABLE_TYPE] == TOUCH_MULTITOUCHSCREEN_T9)
+ ts->finger_type = ts->object_table[i].report_ids;
+ }
+
+ return 0;
+}
+
+struct atmel_i2c_platform_data *atmel_ts_get_pdata(struct i2c_client *client)
+{
+ struct device_node *node = client->dev.of_node;
+ struct atmel_i2c_platform_data *pdata = client->dev.platform_data;
+ u32 data[8];
+
+ if (pdata)
+ return pdata;
+
+ if (!node)
+ return NULL;
+
+ pdata = devm_kzalloc(&client->dev, sizeof(struct atmel_i2c_platform_data),
+ GFP_KERNEL);
+ pdata->gpio_irq = of_get_named_gpio(node, "atmel-ts,gpio-irq", 0);
+ pdata->gpio_reset = of_get_named_gpio(node, "atmel-ts,gpio-reset", 0);
+
+ of_property_read_u32_array(node, "atmel-ts,abs", &data[0], 8);
+ pdata->abs_x_min = data[0];
+ pdata->abs_x_max = data[1];
+ pdata->abs_y_min = data[2];
+ pdata->abs_y_max = data[3];
+ pdata->abs_pressure_min = data[4];
+ pdata->abs_pressure_max = data[5];
+ pdata->abs_width_min = data[6];
+ pdata->abs_width_max = data[7];
+
+ of_property_read_u8_array(node, "atmel-ts,cfg_t6", &pdata->config_T6[0], 6);
+ of_property_read_u8_array(node, "atmel-ts,cfg_t7", &pdata->config_T7[0], 3);
+ of_property_read_u8_array(node, "atmel-ts,cfg_t8", &pdata->config_T8[0], 10);
+ of_property_read_u8_array(node, "atmel-ts,cfg_t9", &pdata->config_T9[0], 35);
+ of_property_read_u8_array(node, "atmel-ts,cfg_t15", &pdata->config_T15[0], 11);
+ of_property_read_u8_array(node, "atmel-ts,cfg_t19", &pdata->config_T19[0], 16);
+ of_property_read_u8_array(node, "atmel-ts,cfg_t23", &pdata->config_T23[0], 15);
+ of_property_read_u8_array(node, "atmel-ts,cfg_t25", &pdata->config_T25[0], 14);
+ of_property_read_u8_array(node, "atmel-ts,cfg_t40", &pdata->config_T40[0], 5);
+ of_property_read_u8_array(node, "atmel-ts,cfg_t42", &pdata->config_T42[0], 8);
+ of_property_read_u8_array(node, "atmel-ts,cfg_t46", &pdata->config_T46[0], 9);
+ of_property_read_u8_array(node, "atmel-ts,cfg_t47", &pdata->config_T47[0], 10);
+ of_property_read_u8_array(node, "atmel-ts,cfg_t48", &pdata->config_T48[0], 54);
+ of_property_read_u8_array(node, "atmel-ts,object_crc", &pdata->object_crc[0], 3);
+ of_property_read_u8_array(node, "atmel-ts,cable_config", &pdata->cable_config[0], 4);
+ of_property_read_u8_array(node, "atmel-ts,cable_config_t7", &pdata->cable_config_T7[0], 3);
+ of_property_read_u8_array(node, "atmel-ts,cable_config_t8", &pdata->cable_config_T8[0], 10);
+ of_property_read_u8_array(node, "atmel-ts,cable_config_t46", &pdata->cable_config_T46[0], 9);
+ of_property_read_u8_array(node, "atmel-ts,cable_config_t48", &pdata->cable_config_T48[0], 54);
+ of_property_read_u8_array(node, "atmel-ts,noise_config", &pdata->noise_config[0], 3);
+ of_property_read_u16_array(node, "atmel-ts,filter_level", &pdata->filter_level[0], 4);
+ of_property_read_u8_array(node, "atmel-ts,gcaf_level", &pdata->GCAF_level[0], 5);
+ of_property_read_u8_array(node, "atmel-ts,atch_nor", &pdata->ATCH_NOR[0], 6);
+ of_property_read_u8_array(node, "atmel-ts,atch_nor_20s", &pdata->ATCH_NOR_20S[0], 6);
+
+ return pdata;
+}
+
+static int atmel_ts_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct atmel_ts_data *ts;
+ struct atmel_i2c_platform_data *pdata;
+ int ret = 0, intr = 0;
+ uint8_t loop_i;
+ struct i2c_msg msg[2];
+ uint8_t data[16];
+ uint8_t CRC_check = 0;
+
+ client->dev.init_name = "atmel-ts";
+ LDO = regulator_get(&client->dev, "ldo");
+ if (IS_ERR(LDO)) {
+ dev_err(&client->dev, "no regulator found\n");
+ LDO = NULL;
+ } else {
+ ret = regulator_enable(LDO);
+ if (!ret)
+ ret = regulator_set_voltage(LDO, LDO_POWR_VOLTAGE, LDO_POWR_VOLTAGE);
+ if (ret)
+ dev_err(&client->dev, "k3ts, %s: failed to set LDO\n", __func__);
+ }
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ dev_err(&client->dev, "k3ts, %s: need I2C_FUNC_I2C\n", __func__);
+ ret = -ENODEV;
+ goto err_check_functionality_failed;
+ }
+
+ ts = kzalloc(sizeof(struct atmel_ts_data), GFP_KERNEL);
+ if (ts == NULL) {
+ ret = -ENOMEM;
+ goto err_alloc_data_failed;
+ }
+
+ ts->unlock_flag = 0;
+ mutex_init(&ts->lock);
+
+ ts->atmel_wq = create_singlethread_workqueue("atmel_wq");
+ if (!ts->atmel_wq) {
+ dev_err(&client->dev, "k3ts, %s: create workqueue failed\n", __func__);
+ ret = -ENOMEM;
+ goto err_cread_wq_failed;
+ }
+
+ ts->client = client;
+ i2c_set_clientdata(client, ts);
+
+ pdata = atmel_ts_get_pdata(client);
+ ts->pdata = pdata;
+
+ if (pdata) {
+ ts->power = pdata->power;
+ intr = pdata->gpio_irq;
+ client->irq = gpio_to_irq(intr);
+ }
+ if (ts->power)
+ ret = ts->power(1);
+ ret = gpio_request(intr, "gpio_tp_intr");
+ if (ret) {
+ dev_err(&client->dev, "gpio_request %d failed\n", intr);
+ goto err_request_gpio_failed;
+ }
+ ret = gpio_direction_input(intr);
+ if (ret) {
+ dev_err(&client->dev, "k3ts, %s: gpio_direction_input failed %d\n", __func__, intr);
+ goto err_gpio_direction_failed;
+ }
+
+ ret = gpio_request(ts->pdata->gpio_reset, "gpio_tp_reset");
+ if (ret) {
+ dev_err(&client->dev, "k3ts, %s: gpio_request failed %d, ret = %d\n",
+ __func__, ts->pdata->gpio_reset, ret);
+ goto err_request_gpio_reset_failed;
+ }
+
+ gpio_direction_output(ts->pdata->gpio_reset, 1);
+ mdelay(5);
+ gpio_direction_output(ts->pdata->gpio_reset, 0);
+ mdelay(10);
+ gpio_direction_output(ts->pdata->gpio_reset, 1);
+ mdelay(50);
+
+ for (loop_i = 0; loop_i < 10; loop_i++) {
+ if (!gpio_get_value(intr))
+ break;
+ msleep(10);
+ }
+
+ if (loop_i == 10)
+ dev_err(&client->dev, "k3ts, %s: No Messages\n", __func__);
+
+ /* read message*/
+ msg[0].addr = ts->client->addr;
+ msg[0].flags = I2C_M_RD;
+ msg[0].len = 7;
+ msg[0].buf = data;
+ ret = i2c_transfer(client->adapter, msg, 1);
+
+ if (ret < 0) {
+ dev_err(&client->dev, "k3ts, %s: No Atmel chip inside\n", __func__);
+ goto err_detect_failed;
+ }
+ if (ts->power)
+ ret = ts->power(2);
+
+ if (data[MSG_RID] == 0x01 &&
+ (data[T6_MSG_STATUS] & (T6_MSG_STATUS_SIGERR|T6_MSG_STATUS_COMSERR))) {
+ dev_err(&client->dev, "k3ts, %s: init err: %x\n", __func__, data[1]);
+ goto err_detect_failed;
+ } else {
+ for (loop_i = 0; loop_i < 10; loop_i++) {
+ if (gpio_get_value(intr)) {
+ dev_err(&client->dev, "k3ts, %s: No more message\n", __func__);
+ break;
+ }
+ ret = i2c_transfer(client->adapter, msg, 1);
+ msleep(10);
+ }
+ }
+
+ /* Read the info block data. */
+ ts->id = kzalloc(sizeof(struct info_id_t), GFP_KERNEL);
+ if (ts->id == NULL) {
+ dev_err(&client->dev, "k3ts, %s: allocate info_id_t failed\n", __func__);
+ goto err_alloc_failed;
+ }
+ ret = i2c_atmel_read(client, 0x00, data, 7);
+
+ ts->id->family_id = data[INFO_BLK_FID];
+ ts->id->variant_id = data[INFO_BLK_VID];
+ if (ts->id->family_id == 0x80 && ts->id->variant_id == 0x10)
+ ts->id->version = data[INFO_BLK_VER] + 6;
+ else
+ ts->id->version = data[INFO_BLK_VER];
+
+ ts->id->build = data[INFO_BLK_BUILD];
+ ts->id->matrix_x_size = data[INFO_BLK_XSIZE];
+ ts->id->matrix_y_size = data[INFO_BLK_YSIZE];
+ ts->id->num_declared_objects = data[INFO_BLK_OBJS];
+
+ /* Read object table. */
+ ret = read_object_table(ts);
+ if (ret < 0)
+ goto err_read_table_failed;
+
+
+ if (pdata) {
+ ts->finger_support = pdata->config_T9[T9_CFG_NUMTOUCH];
+
+ /* OBJECT CONFIG CRC check */
+ if (pdata->object_crc[0]) {
+ ret = i2c_atmel_write_byte_data(client,
+ get_object_address(ts, GEN_COMMANDPROCESSOR_T6) +
+ T6_CFG_CALIBRATE, 0x55);
+ for (loop_i = 0; loop_i < 10; loop_i++) {
+ if (!gpio_get_value(intr)) {
+ ret = i2c_atmel_read(ts->client, get_object_address(ts,
+ GEN_MESSAGEPROCESSOR_T5), data, 5);
+ if (data[MSG_RID] == get_rid(ts, GEN_COMMANDPROCESSOR_T6))
+ break;
+ }
+ msleep(10);
+ }
+ if (loop_i == 10)
+ dev_err(&client->dev, "k3ts, %s: No checksum read\n", __func__);
+ else {
+ dev_info(&client->dev, "k3ts, %s: CRC print : %x, %x, %x\n", __func__,
+ data[T6_MSG_CHECKSUM + 0], data[T6_MSG_CHECKSUM + 1], data[T6_MSG_CHECKSUM + 2]);
+ for (loop_i = 0; loop_i < 3; loop_i++) {
+ if (pdata->object_crc[loop_i] != data[T6_MSG_CHECKSUM + loop_i]) {
+ dev_err(&client->dev,
+ "k3ts, %s: CRC Error: %x, %x\n", __func__,
+ pdata->object_crc[loop_i],
+ data[T6_MSG_CHECKSUM + loop_i]);
+ break;
+ }
+ }
+ if (loop_i == 3) {
+ dev_info(&client->dev, "k3ts, %s: CRC passed: ", __func__);
+ for (loop_i = 0; loop_i < 3; loop_i++)
+ pr_info("0x%2.2X ", pdata->object_crc[loop_i]);
+ pr_info("\n");
+ CRC_check = 1;/*means CRC check OK*/
+ }
+ }
+ }
+ ts->abs_x_min = pdata->abs_x_min;
+ ts->abs_x_max = pdata->abs_x_max;
+ ts->abs_y_min = pdata->abs_y_min;
+ ts->abs_y_max = pdata->abs_y_max;
+ ts->abs_pressure_min = pdata->abs_pressure_min;
+ ts->abs_pressure_max = pdata->abs_pressure_max;
+ ts->abs_width_min = pdata->abs_width_min;
+ ts->abs_width_max = pdata->abs_width_max;
+
+ ts->GCAF_level = pdata->GCAF_level;
+ if (ts->id->version >= 0x10) {
+ ts->ATCH_EXT = &pdata->config_T8[6];
+ ts->timestamp = jiffies + 60 * HZ;
+ }
+ ts->ATCH_NOR = pdata->ATCH_NOR;
+ ts->ATCH_NOR_20S = pdata->ATCH_NOR_20S;
+ ts->filter_level = pdata->filter_level;
+
+ ts->config_setting[NONE].config_T7
+ = ts->config_setting[CONNECTED].config_T7
+ = pdata->config_T7;
+ ts->config_setting[NONE].config_T8 = pdata->config_T8;
+ ts->config_setting[CONNECTED].config_T8 = pdata->cable_config_T8;
+ ts->config_setting[NONE].config_T9 = pdata->config_T9;
+ ts->config_setting[NONE].config_T22 = pdata->config_T22;
+ ts->config_setting[NONE].config_T28 = pdata->config_T28;
+ ts->config_setting[NONE].config_T46 = pdata->config_T46;
+ ts->config_setting[NONE].config_T48 = pdata->config_T48;
+ ts->config_setting[CONNECTED].config_T46 = pdata->cable_config_T46;
+ ts->config_setting[CONNECTED].config_T48 = pdata->cable_config_T48;
+
+ if (pdata->noise_config[0])
+ for (loop_i = 0; loop_i < 3; loop_i++)
+ ts->noise_config[loop_i] = pdata->noise_config[loop_i];
+
+ if (pdata->cable_config[0]) {
+ ts->config_setting[NONE].config[CB_TCHTHR] =
+ pdata->config_T9[T9_CFG_TCHTHR];
+ ts->config_setting[NONE].config[CB_NOISETHR] =
+ pdata->config_T22[T22_CFG_NOISETHR];
+ ts->config_setting[NONE].config[CB_IDLEGCAFDEPTH] =
+ pdata->config_T28[T28_CFG_IDLEGCAFDEPTH];
+ ts->config_setting[NONE].config[CB_ACTVGCAFDEPTH] =
+ pdata->config_T28[T28_CFG_ACTVGCAFDEPTH];
+ for (loop_i = 0; loop_i < 4; loop_i++)
+ ts->config_setting[CONNECTED].config[loop_i] =
+ pdata->cable_config[loop_i];
+ ts->GCAF_sample =
+ ts->config_setting[CONNECTED].config[CB_ACTVGCAFDEPTH];
+ if (ts->id->version >= 0x20)
+ ts->noisethr = pdata->cable_config[CB_TCHTHR] -
+ pdata->config_T9[T9_CFG_TCHHYST];
+ else
+ ts->noisethr = pdata->cable_config[CB_TCHTHR];
+ ts->noisethr_config =
+ ts->config_setting[CONNECTED].config[CB_NOISETHR];
+ } else {
+ if (pdata->cable_config_T7[0])
+ ts->config_setting[CONNECTED].config_T7 =
+ pdata->cable_config_T7;
+ if (pdata->cable_config_T8[0])
+ ts->config_setting[CONNECTED].config_T8 =
+ pdata->cable_config_T8;
+ if (pdata->cable_config_T9[0]) {
+ ts->config_setting[CONNECTED].config_T9 =
+ pdata->cable_config_T9;
+ ts->config_setting[CONNECTED].config_T22 =
+ pdata->cable_config_T22;
+ ts->config_setting[CONNECTED].config_T28 =
+ pdata->cable_config_T28;
+ ts->GCAF_sample =
+ ts->config_setting[CONNECTED].config_T28[T28_CFG_ACTVGCAFDEPTH];
+ }
+ if (ts->status == CONNECTED)
+ ts->noisethr = (ts->id->version >= 0x20) ?
+ pdata->cable_config_T9[T9_CFG_TCHTHR] - pdata->cable_config_T9[T9_CFG_TCHHYST] :
+ pdata->cable_config_T9[T9_CFG_TCHTHR];
+ else
+ ts->noisethr = (ts->id->version >= 0x20) ?
+ pdata->config_T9[T9_CFG_TCHTHR] - pdata->config_T9[T9_CFG_TCHHYST] :
+ pdata->config_T9[T9_CFG_TCHTHR];
+ ts->noisethr_config = pdata->cable_config_T22[T22_CFG_NOISETHR];
+
+ }
+
+ i2c_atmel_write(ts->client,
+ get_object_address(ts, GEN_COMMANDPROCESSOR_T6),
+ pdata->config_T6,
+ get_object_size(ts, GEN_COMMANDPROCESSOR_T6));
+ i2c_atmel_write(ts->client,
+ get_object_address(ts, GEN_POWERCONFIG_T7),
+ pdata->config_T7,
+ get_object_size(ts, GEN_POWERCONFIG_T7));
+ i2c_atmel_write(ts->client,
+ get_object_address(ts, GEN_ACQUISITIONCONFIG_T8),
+ pdata->config_T8,
+ get_object_size(ts, GEN_ACQUISITIONCONFIG_T8));
+ i2c_atmel_write(ts->client,
+ get_object_address(ts, TOUCH_MULTITOUCHSCREEN_T9),
+ pdata->config_T9,
+ get_object_size(ts, TOUCH_MULTITOUCHSCREEN_T9));
+ i2c_atmel_write(ts->client,
+ get_object_address(ts, TOUCH_KEYARRAY_T15),
+ pdata->config_T15,
+ get_object_size(ts, TOUCH_KEYARRAY_T15));
+ i2c_atmel_write(ts->client,
+ get_object_address(ts, SPT_GPIOPWM_T19),
+ pdata->config_T19,
+ get_object_size(ts, SPT_GPIOPWM_T19));
+
+ i2c_atmel_write(ts->client,
+ get_object_address(ts, PROCI_GRIPSUPPRESSION_T40),
+ pdata->config_T40,
+ get_object_size(ts, PROCI_GRIPSUPPRESSION_T40));
+
+ i2c_atmel_write(ts->client,
+ get_object_address(ts, PROCI_TOUCHSUPPRESSION_T42),
+ pdata->config_T42,
+ get_object_size(ts, PROCI_TOUCHSUPPRESSION_T42));
+ i2c_atmel_write(ts->client,
+ get_object_address(ts, PROCG_NOISESUPPRESSION_T48),
+ pdata->config_T48,
+ get_object_size(ts, PROCG_NOISESUPPRESSION_T48));
+ i2c_atmel_write(ts->client,
+ get_object_address(ts, TOUCH_PROXIMITY_T23),
+ pdata->config_T23,
+ get_object_size(ts, TOUCH_PROXIMITY_T23));
+ i2c_atmel_write(ts->client,
+ get_object_address(ts, SPT_SELFTEST_T25),
+ pdata->config_T25,
+ get_object_size(ts, SPT_SELFTEST_T25));
+ i2c_atmel_write(ts->client,
+ get_object_address(ts, SPT_CTECONFIG_T46),
+ pdata->config_T46,
+ get_object_size(ts, SPT_CTECONFIG_T46));
+ i2c_atmel_write(ts->client,
+ get_object_address(ts, PROCI_STYLUS_T47),
+ pdata->config_T47,
+ get_object_size(ts, PROCI_STYLUS_T47));
+
+ ret = i2c_atmel_write_byte_data(client,
+ get_object_address(ts, GEN_COMMANDPROCESSOR_T6) +
+ T6_CFG_BACKUPNV, 0x55);
+
+ for (loop_i = 0; loop_i < 10; loop_i++) {
+ if (!gpio_get_value(intr))
+ break;
+ dev_err(&client->dev, "k3ts, %s: wait for Message(%d)\n", __func__, loop_i + 1);
+ msleep(10);
+ }
+
+ i2c_atmel_read(client,
+ get_object_address(ts, GEN_MESSAGEPROCESSOR_T5), data, 7);
+
+ ret = i2c_atmel_write_byte_data(client,
+ get_object_address(ts, GEN_COMMANDPROCESSOR_T6) +
+ T6_CFG_RESET, 0x11);/*reset*/
+ msleep(100);
+
+ if (ts->status == CONNECTED) {
+ if (ts->config_setting[CONNECTED].config_T8 != NULL)
+ i2c_atmel_write(ts->client,
+ get_object_address(ts, GEN_ACQUISITIONCONFIG_T8),
+ ts->config_setting[CONNECTED].config_T8,
+ get_object_size(ts, GEN_ACQUISITIONCONFIG_T8));
+ if (ts->config_setting[CONNECTED].config_T46 != NULL)
+ i2c_atmel_write(ts->client,
+ get_object_address(ts, SPT_CTECONFIG_T46),
+ ts->config_setting[CONNECTED].config_T46,
+ get_object_size(ts, SPT_CTECONFIG_T46));
+ if (ts->config_setting[CONNECTED].config_T48 != NULL) {
+ i2c_atmel_write(ts->client,
+ get_object_address(ts, PROCG_NOISESUPPRESSION_T48),
+ ts->config_setting[CONNECTED].config_T48,
+ get_object_size(ts, PROCG_NOISESUPPRESSION_T48));
+ }
+ }
+ }
+ ts->calibration_confirm = 0;
+ ts->input_dev = input_allocate_device();
+ if (ts->input_dev == NULL) {
+ ret = -ENOMEM;
+ dev_err(&client->dev, "k3ts, %s: Failed to allocate input device\n", __func__);
+ goto err_input_dev_alloc_failed;
+ }
+ /*Modified by z181527 for Debug Only*/
+ ts->input_dev->name = "synaptics"/*"atmel-touchscreen"*/;
+ set_bit(EV_SYN, ts->input_dev->evbit);
+ set_bit(EV_KEY, ts->input_dev->evbit);
+ set_bit(BTN_TOUCH, ts->input_dev->keybit);
+ set_bit(BTN_2, ts->input_dev->keybit);
+ set_bit(EV_ABS, ts->input_dev->evbit);
+ set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
+ input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X,
+ ts->abs_x_min, ts->abs_x_max, 0, 0);
+ input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y,
+ ts->abs_y_min, ts->abs_y_max, 0, 0);
+ input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR,
+ ts->abs_pressure_min, ts->abs_pressure_max,
+ 0, 0);
+ input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR,
+ ts->abs_width_min, ts->abs_width_max, 0, 0);
+
+ ret = input_register_device(ts->input_dev);
+ if (ret) {
+ dev_err(&client->dev,
+ "k3ts, %s: atmel_ts_probe: Unable to register %s input device\n", __func__,
+ ts->input_dev->name);
+ goto err_input_register_device_failed;
+ }
+
+ ret = request_threaded_irq(client->irq, NULL, atmel_interrupt_fun,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ client->name, ts);
+ if (ret)
+ dev_err(&client->dev, "k3ts, %s: request_irq failed\n", __func__);
+
+ private_ts = ts;
+
+ dev_info(&client->dev, "k3ts, %s: probe %s successfully\n", __func__,
+ ts->input_dev->name);
+
+ return 0;
+
+err_input_register_device_failed:
+ input_free_device(ts->input_dev);
+err_input_dev_alloc_failed:
+err_read_table_failed:
+ kfree(ts->id);
+err_alloc_failed:
+err_detect_failed:
+err_gpio_direction_failed:
+err_request_gpio_reset_failed:
+ gpio_free(ts->pdata->gpio_reset);
+ gpio_free(intr);
+err_request_gpio_failed:
+ destroy_workqueue(ts->atmel_wq);
+err_cread_wq_failed:
+ kfree(ts);
+err_alloc_data_failed:
+err_check_functionality_failed:
+ if (LDO != NULL) {
+ regulator_disable(LDO);
+ regulator_put(LDO);
+ }
+ return ret;
+}
+
+static int atmel_ts_remove(struct i2c_client *client)
+{
+ struct atmel_ts_data *ts = i2c_get_clientdata(client);
+
+ free_irq(client->irq, ts);
+
+ destroy_workqueue(ts->atmel_wq);
+ input_unregister_device(ts->input_dev);
+ kfree(ts);
+
+ regulator_disable(LDO);
+ regulator_put(LDO);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int atmel_ts_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct atmel_ts_data *ts = i2c_get_clientdata(client);
+ struct atmel_i2c_platform_data *pdata = ts->pdata;
+ uint8_t data[7];
+ int ret = 0;
+
+ mutex_lock(&ts->lock);
+ ts->finger_pressed = 0;
+ ts->finger_count = 0;
+ ts->first_pressed = 0;
+
+ if (ts->id->version >= 0x10) {
+ ts->pre_data[0] = 0;
+ ret = i2c_atmel_write(ts->client,
+ get_object_address(ts, GEN_ACQUISITIONCONFIG_T8) + T8_CFG_ATCHCALST,
+ ts->ATCH_EXT, 4);
+ if (ret < 0)
+ pr_err("k3ts, %s: failed to write config T8\n", __func__);
+ }
+
+ ret = i2c_atmel_write_byte_data(client,
+ get_object_address(ts, GEN_POWERCONFIG_T7) + T7_CFG_IDLEACQINT, 0x0);
+ if (ret < 0)
+ pr_err("k3ts, %s: failed to write config T7\n", __func__);
+
+ ret = i2c_atmel_write_byte_data(client,
+ get_object_address(ts, GEN_POWERCONFIG_T7) + T7_CFG_ACTVACQINT, 0x0);
+ if (ret < 0)
+ pr_err("k3ts, %s: failed to write config T7\n", __func__);
+
+ /* Read T5 until gpio_irq is HIGH level */
+ if (!gpio_get_value(pdata->gpio_irq)) {
+ ret = i2c_atmel_read(ts->client, get_object_address(ts,
+ GEN_MESSAGEPROCESSOR_T5), data, 7);
+ if (ret < 0) {
+ pr_err("k3ts, %s: failed to read T5\n", __func__);
+ }
+ }
+
+ mutex_unlock(&ts->lock);
+
+ pr_info("[%s]: -\n", __func__);
+ return 0;
+}
+
+static int atmel_ts_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct atmel_ts_data *ts = i2c_get_clientdata(client);
+ int ret = 0;
+
+ pr_info("[%s]: +\n", __func__);
+
+ mutex_lock(&ts->lock);
+ if (ts->id->version >= 0x10)
+ ts->timestamp = jiffies;
+
+ ts->unlock_flag = 0;
+
+ ret = i2c_atmel_write(ts->client,
+ get_object_address(ts, GEN_POWERCONFIG_T7),
+ ts->config_setting[ts->status].config_T7,
+ get_object_size(ts, GEN_POWERCONFIG_T7));
+ if (ret < 0)
+ pr_err("k3ts, %s: failed to write config T7\n", __func__);
+
+ ts->calibration_confirm = 0;
+ msleep(1);
+
+ ret = i2c_atmel_write(ts->client,
+ get_object_address(ts, GEN_ACQUISITIONCONFIG_T8) +
+ T8_CFG_TCHAUTOCAL, ts->ATCH_NOR, 6);
+ if (ret < 0)
+ pr_err("k3ts, %s: failed to write config T8\n", __func__);
+
+ ret = i2c_atmel_write_byte_data(client,
+ get_object_address(ts, GEN_COMMANDPROCESSOR_T6) +
+ T6_CFG_CALIBRATE, 0x55);
+ if (ret < 0)
+ pr_err("k3ts, %s: failed to write config T6\n", __func__);
+
+ mutex_unlock(&ts->lock);
+
+ pr_info("[%s]: -\n", __func__);
+
+ return 0;
+}
+#endif
+static SIMPLE_DEV_PM_OPS(atmel_ts_pm_ops, atmel_ts_suspend, atmel_ts_resume);
+
+static const struct i2c_device_id atml_ts_i2c_id[] = {
+ { ATMEL_MXT224E_NAME, 0 },
+ { }
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id atmel_ts_dt_ids[] = {
+ { .compatible = "atmel,ts-mxt224e", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, atmel_ts_dt_ids);
+#endif
+
+static struct i2c_driver atmel_ts_driver = {
+ .id_table = atml_ts_i2c_id,
+ .probe = atmel_ts_probe,
+ .remove = atmel_ts_remove,
+ .driver = {
+ .of_match_table = of_match_ptr(atmel_ts_dt_ids),
+ .name = ATMEL_MXT224E_NAME,
+ .pm = &atmel_ts_pm_ops,
+ },
+};
+module_i2c_driver(atmel_ts_driver);
+
+MODULE_DESCRIPTION("ATMEL Touch driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index a5e54f0d6a73..5767b22a139c 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -442,6 +442,12 @@ config MFD_PM8XXX_IRQ
This is required to use certain other PM 8xxx features, such as GPIO
and MPP.
+config MFD_R63306
+ tristate "Support R63306 Graphics Liquid Crystal Controller"
+ select MFD_CORE
+ help
+ This supports for Renesas R63306 Graphics Liquid Crystal Controller.
+
config MFD_RDC321X
tristate "RDC R-321x southbridge"
select MFD_CORE
@@ -1116,6 +1122,14 @@ config MFD_WM8994
core support for the WM8994, in order to use the actual
functionaltiy of the device other drivers must be enabled.
+config MFD_HI6421_PMIC
+ tristate "HiSilicon Hi6421 PMU/Codec IC"
+ depends on OF
+ help
+ This driver supports HiSilicon Hi6421 power management and codec IC,
+ including regulators, codec, ADCs, Coulomb counter, etc. Memory
+ mapped I/O ports are the way of communication with it.
+
endmenu
endif
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 3a0120315aa3..f3b3b48f97c4 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -142,6 +142,7 @@ obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o
obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o omap-usb-tll.o
obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o
obj-$(CONFIG_MFD_PM8XXX_IRQ) += pm8xxx-irq.o
+obj-$(CONFIG_MFD_R63306) += r63306.o
obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o
obj-$(CONFIG_MFD_TPS65090) += tps65090.o
obj-$(CONFIG_MFD_AAT2870_CORE) += aat2870-core.o
@@ -156,3 +157,4 @@ obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-config.o vexpress-sysreg.o
obj-$(CONFIG_VEXPRESS_SPC) += vexpress-spc.o
obj-$(CONFIG_MFD_RETU) += retu-mfd.o
obj-$(CONFIG_MFD_AS3711) += as3711.o
+obj-$(CONFIG_MFD_HI6421_PMIC) += hi6421-pmic-core.o
diff --git a/drivers/mfd/hi6421-pmic-core.c b/drivers/mfd/hi6421-pmic-core.c
new file mode 100644
index 000000000000..1ef6d4e16172
--- /dev/null
+++ b/drivers/mfd/hi6421-pmic-core.c
@@ -0,0 +1,310 @@
+/*
+ * Device driver for regulators in Hi6421 IC
+ *
+ * Copyright (c) 2013 Linaro Ltd.
+ * Copyright (c) 2011 Hisilicon.
+ *
+ * Guodong Xu <guodong.xu@linaro.org>
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/of_irq.h>
+#include <linux/mfd/hi6421-pmic.h>
+
+#include <asm/mach/irq.h>
+
+/* 8-bit register offset in PMIC */
+#define HI6421_REG_IRQ1 1
+#define HI6421_REG_IRQ2 2
+#define HI6421_REG_IRQ3 3
+#define HI6421_REG_IRQM1 4
+#define HI6421_REG_IRQM2 5
+#define HI6421_REG_IRQM3 6
+
+static struct of_device_id of_hi6421_pmic_child_match_tbl[] = {
+ /* regulators */
+ {
+ .compatible = "hisilicon,hi6421-ldo",
+ },
+ {
+ .compatible = "hisilicon,hi6421-buck012",
+ },
+ {
+ .compatible = "hisilicon,hi6421-buck345",
+ },
+ { /* end */ }
+};
+
+static struct of_device_id of_hi6421_pmic_match_tbl[] = {
+ {
+ .compatible = "hisilicon,hi6421-pmic",
+ },
+ { /* end */ }
+};
+
+/*
+ * The PMIC register is only 8-bit.
+ * Hisilicon SoC use hardware to map PMIC register into SoC mapping.
+ * At here, we are accessing SoC register with 32-bit.
+ */
+u32 hi6421_pmic_read(struct hi6421_pmic *pmic, int reg)
+{
+ unsigned long flags;
+ u32 ret;
+ spin_lock_irqsave(&pmic->lock, flags);
+ ret = readl_relaxed(pmic->regs + (reg << 2));
+ spin_unlock_irqrestore(&pmic->lock, flags);
+ return ret;
+}
+EXPORT_SYMBOL(hi6421_pmic_read);
+
+void hi6421_pmic_write(struct hi6421_pmic *pmic, int reg, u32 val)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&pmic->lock, flags);
+ writel_relaxed(val, pmic->regs + (reg << 2));
+ spin_unlock_irqrestore(&pmic->lock, flags);
+}
+EXPORT_SYMBOL(hi6421_pmic_write);
+
+void hi6421_pmic_rmw(struct hi6421_pmic *pmic, int reg,
+ u32 mask, u32 bits)
+{
+ u32 data;
+
+ spin_lock(&pmic->lock);
+ data = readl_relaxed(pmic->regs + (reg << 2)) & ~mask;
+ data |= mask & bits;
+ writel_relaxed(data, pmic->regs + (reg << 2));
+ spin_unlock(&pmic->lock);
+}
+EXPORT_SYMBOL(hi6421_pmic_rmw);
+
+static int hi6421_to_irq(struct hi6421_pmic *pmic, unsigned offset)
+{
+ return irq_find_mapping(pmic->domain, offset);
+}
+
+static irqreturn_t hi6421_irq_handler(int irq, void *data)
+{
+ struct hi6421_pmic *pmic = (struct hi6421_pmic *)data;
+ unsigned long pending;
+ int i, offset, index;
+
+
+ for (i = HI6421_REG_IRQ1; i <= HI6421_REG_IRQ3; i++) {
+ spin_lock(&pmic->lock);
+ pending = readl_relaxed(pmic->regs + (i << 2));
+ pending &= HI6421_MASK_FIELD;
+ writel_relaxed(pending, pmic->regs + ((i + 3) << 2));
+ spin_unlock(&pmic->lock);
+
+ if (pending) {
+ for_each_set_bit(offset, &pending, HI6421_BITS) {
+ index = offset + (i - HI6421_REG_IRQ1) * HI6421_BITS;
+ generic_handle_irq(hi6421_to_irq(pmic, index));
+ }
+ }
+
+ spin_lock(&pmic->lock);
+ writel_relaxed(0, pmic->regs + ((i + 3) << 2));
+ writel_relaxed(pending, pmic->regs + (i << 2));
+ spin_unlock(&pmic->lock);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void hi6421_irq_mask(struct irq_data *d)
+{
+ struct hi6421_pmic *pmic = irq_data_get_irq_chip_data(d);
+ u32 data, offset;
+
+ offset = ((irqd_to_hwirq(d) >> 3) + HI6421_REG_IRQM1) << 2;
+ spin_lock(&pmic->lock);
+ data = readl_relaxed(pmic->regs + offset);
+ data |= irqd_to_hwirq(d) % 8;
+ writel_relaxed(data, pmic->regs + offset);
+ spin_unlock(&pmic->lock);
+}
+
+static void hi6421_irq_unmask(struct irq_data *d)
+{
+ struct hi6421_pmic *pmic = irq_data_get_irq_chip_data(d);
+ u32 data, offset;
+
+ offset = ((irqd_to_hwirq(d) >> 3) + HI6421_REG_IRQM1) << 2;
+ spin_lock(&pmic->lock);
+ data = readl_relaxed(pmic->regs + offset);
+ data &= ~(irqd_to_hwirq(d) % 8);
+ writel_relaxed(data, pmic->regs + offset);
+ spin_unlock(&pmic->lock);
+}
+
+static struct irq_chip hi6421_irqchip = {
+ .name = "pmic",
+ .irq_mask = hi6421_irq_mask,
+ .irq_unmask = hi6421_irq_unmask,
+};
+
+static int hi6421_irq_map(struct irq_domain *d, unsigned int virq,
+ irq_hw_number_t hw)
+{
+ struct hi6421_pmic *pmic = d->host_data;
+
+ irq_set_chip_and_handler_name(virq, &hi6421_irqchip,
+ handle_simple_irq, "hi6421");
+ irq_set_chip_data(virq, pmic);
+ irq_set_irq_type(virq, IRQ_TYPE_NONE);
+
+ return 0;
+}
+
+static struct irq_domain_ops hi6421_domain_ops = {
+ .map = hi6421_irq_map,
+ .xlate = irq_domain_xlate_twocell,
+};
+
+static int hi6421_pmic_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct hi6421_pmic *pmic = NULL;
+ enum of_gpio_flags flags;
+ int i, ret;
+
+ pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL);
+ if (!pmic) {
+ dev_err(dev, "cannot allocate hi6421_pmic device info\n");
+ return -ENOMEM;
+ }
+
+ mutex_init(&pmic->enable_mutex);
+ /* get resources */
+ pmic->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!pmic->res) {
+ dev_err(dev, "platform_get_resource err\n");
+ return -ENOENT;
+ }
+
+ if (!devm_request_mem_region(dev, pmic->res->start,
+ resource_size(pmic->res),
+ pdev->name)) {
+ dev_err(dev, "cannot claim register memory\n");
+ return -ENOMEM;
+ }
+
+ pmic->regs = devm_ioremap(dev, pmic->res->start,
+ resource_size(pmic->res));
+ if (!pmic->regs) {
+ dev_err(dev, "cannot map register memory\n");
+ return -ENOMEM;
+ }
+
+ /* TODO: get and enable clk request */
+
+ spin_lock_init(&pmic->lock);
+
+ pmic->gpio = of_get_gpio_flags(np, 0, &flags);
+ if (pmic->gpio < 0)
+ return pmic->gpio;
+ if (!gpio_is_valid(pmic->gpio))
+ return -EINVAL;
+ ret = gpio_request_one(pmic->gpio, GPIOF_IN, "pmic");
+ if (ret < 0) {
+ dev_err(dev, "failed to request gpio%d\n", pmic->gpio);
+ return ret;
+ }
+ pmic->irq = gpio_to_irq(pmic->gpio);
+ /* clear IRQ status */
+ spin_lock(&pmic->lock);
+ writel_relaxed(0xff, pmic->regs + (HI6421_REG_IRQ1 << 2));
+ writel_relaxed(0xff, pmic->regs + (HI6421_REG_IRQ2 << 2));
+ writel_relaxed(0xff, pmic->regs + (HI6421_REG_IRQ3 << 2));
+ spin_unlock(&pmic->lock);
+
+ pmic->domain = irq_domain_add_simple(np, HI6421_NR_IRQ, 0,
+ &hi6421_domain_ops, pmic);
+ if (!pmic->domain)
+ return -ENODEV;
+
+ for (i = 0; i < HI6421_NR_IRQ; i++) {
+ ret = irq_create_mapping(pmic->domain, i);
+ if (ret == NO_IRQ) {
+ dev_err(dev, "failed mapping hwirq %d\n", i);
+ return -ENOMEM;
+ }
+ }
+
+ ret = request_threaded_irq(pmic->irq, hi6421_irq_handler, NULL,
+ IRQF_TRIGGER_LOW | IRQF_TRIGGER_FALLING | IRQF_NO_SUSPEND,
+ "pmic", pmic);
+
+ platform_set_drvdata(pdev, pmic);
+
+ /* set over-current protection debounce 8ms*/
+ hi6421_pmic_rmw(pmic, OCP_DEB_CTRL_REG, \
+ OCP_DEB_SEL_MASK | OCP_EN_DEBOUNCE_MASK | OCP_AUTO_STOP_MASK, \
+ OCP_DEB_SEL_8MS | OCP_EN_DEBOUNCE_ENABLE);
+
+ /* populate sub nodes */
+ of_platform_populate(np, of_hi6421_pmic_child_match_tbl, NULL, dev);
+
+ return 0;
+}
+
+static int hi6421_pmic_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct hi6421_pmic *pmic = platform_get_drvdata(pdev);
+
+ free_irq(pmic->irq, pmic);
+ gpio_free(pmic->gpio);
+ devm_iounmap(dev, pmic->regs);
+ devm_release_mem_region(dev, pmic->res->start,
+ resource_size(pmic->res));
+ devm_kfree(dev, pmic);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver hi6421_pmic_driver = {
+ .driver = {
+ .name = "hi6421_pmic",
+ .owner = THIS_MODULE,
+ .of_match_table = of_hi6421_pmic_match_tbl,
+ },
+ .probe = hi6421_pmic_probe,
+ .remove = hi6421_pmic_remove,
+};
+module_platform_driver(hi6421_pmic_driver);
+
+MODULE_AUTHOR("Guodong Xu <guodong.xu@linaro.org>");
+MODULE_DESCRIPTION("Hi6421 PMIC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/r63306.c b/drivers/mfd/r63306.c
new file mode 100644
index 000000000000..2bd0f4ad97bc
--- /dev/null
+++ b/drivers/mfd/r63306.c
@@ -0,0 +1,327 @@
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/r63306.h>
+
+#define RENESAS_ID_VENDOR 0x0122
+
+#define DSI_CMD_LEN 32
+
+enum DATA_TYPE {
+ GEN_SHORT_WR_PARAM0 = 0x03,
+ GEN_SHORT_WR_PARAM1 = 0x13,
+ GEN_SHORT_WR_PARAM2 = 0x23,
+ GEN_RD_PARAM0 = 0x04,
+ GEN_RD_PARAM1 = 0x14,
+ GEN_RD_PARAM2 = 0x24,
+ DCS_SHORT_WR_PARAM0 = 0x05,
+ DCS_SHORT_WR_PARAM1 = 0x15,
+ DCS_RD_PARAM0 = 0x06,
+ SET_MAX_PKT = 0x37,
+ NULL_PKT = 0x09,
+ BLANKING_PKT = 0x19,
+ GEN_LONG_WR = 0x29,
+ DCS_LONG_WR = 0x39,
+ PACKED_PIXEL_16B = 0x0e,
+ PACKED_PIXEL_18B = 0x1e,
+ LOOSELY_PACKED_PIXEL_18B = 0x2e,
+ PACKED_PIXEL_24B = 0x3e,
+};
+
+/* 1st byte is DT type, 2nd byte is command, others are parameters. */
+static u8 soft_reset[] = {DCS_SHORT_WR_PARAM0, 0x01};
+static u8 get_power_mode[] = {DCS_RD_PARAM0, 0x0a};
+static u8 get_address_mode[] = {DCS_RD_PARAM0, 0x0b};
+static u8 get_display_mode[] = {DCS_RD_PARAM0, 0x0d};
+static u8 get_signal_mode[] = {DCS_RD_PARAM0, 0x0e};
+static u8 enter_sleep_mode[] = {DCS_SHORT_WR_PARAM0, 0x10};
+static u8 exit_sleep_mode[] = {DCS_SHORT_WR_PARAM0, 0x11};
+static u8 exit_invert_mode[] = {DCS_SHORT_WR_PARAM0, 0x20};
+static u8 enter_invert_mode[] = {DCS_SHORT_WR_PARAM0, 0x21};
+static u8 set_display_off[] = {DCS_SHORT_WR_PARAM0, 0x28};
+static u8 set_display_on[] = {DCS_SHORT_WR_PARAM0, 0x29};
+static u8 set_address_mode[] = {DCS_SHORT_WR_PARAM1, 0x36, 0x0};
+static u8 read_dsi_ctrl[] = {GEN_RD_PARAM1, 0xb6};
+static u8 write_dsi_ctrl[] = {GEN_LONG_WR, 0xb6};
+static u8 read_pfm_pwm_ctrl[] = {GEN_RD_PARAM1, 0xb9};
+static u8 write_pfm_pwm_ctrl[] = {GEN_LONG_WR, 0xb9};
+static u8 read_backlight[] = {GEN_RD_PARAM1, 0xba};
+static u8 read_cabc_ctrl[] = {GEN_RD_PARAM1, 0xbb};
+static u8 write_cabc_ctrl[] = {GEN_LONG_WR, 0xbb};
+static u8 read_cabc_param[] = {GEN_RD_PARAM1, 0xbe};
+static u8 write_cabc_param[] = {GEN_LONG_WR, 0xbe};
+static u8 read_device_code[] = {GEN_RD_PARAM1, 0xbf};
+
+static struct mfd_cell pwm_devs[] = {
+ {
+ .name = "r63306-pwm",
+ .id = -1,
+ .of_compatible = "renesas,r63306-pwm",
+ },
+};
+
+extern int dsi_set_packet(u8 *cmd, int nr_payload);
+
+int dsi_reset(void)
+{
+ u8 cmd[DSI_CMD_LEN];
+
+ memset(cmd, 0, DSI_CMD_LEN);
+ memcpy(cmd, soft_reset, sizeof(soft_reset));
+ return dsi_set_packet(cmd, 1);
+}
+EXPORT_SYMBOL(dsi_reset);
+
+int dsi_enter_sleep(void)
+{
+ u8 cmd[DSI_CMD_LEN];
+
+ memset(cmd, 0, DSI_CMD_LEN);
+ memcpy(cmd, enter_sleep_mode, sizeof(enter_sleep_mode));
+ return dsi_set_packet(cmd, 1);
+}
+EXPORT_SYMBOL(dsi_enter_sleep);
+
+int dsi_exit_sleep(void)
+{
+ u8 cmd[DSI_CMD_LEN];
+
+ memset(cmd, 0, DSI_CMD_LEN);
+ memcpy(cmd, exit_sleep_mode, sizeof(exit_sleep_mode));
+ return dsi_set_packet(cmd, 1);
+}
+EXPORT_SYMBOL(dsi_exit_sleep);
+
+int dsi_get_id(struct r63306_device_id *id)
+{
+ u8 cmd[DSI_CMD_LEN];
+ int ret;
+
+pr_err("#%s, %d\n", __func__, __LINE__);
+ memset(cmd, 0, DSI_CMD_LEN);
+ memcpy(cmd, read_device_code, sizeof(read_device_code));
+ ret = dsi_set_packet(cmd, 5);
+ if (ret)
+ return ret;
+ id->vendor = cmd[2] << 8 | cmd[3];
+ id->product = cmd[4] << 8 | cmd[5];
+ id->revision = cmd[6];
+ return 0;
+}
+EXPORT_SYMBOL(dsi_get_id);
+
+int dsi_get_backlight(int *level)
+{
+ u8 cmd[DSI_CMD_LEN];
+ int ret;
+
+ memset(cmd, 0, DSI_CMD_LEN);
+ memcpy(cmd, read_backlight, sizeof(read_backlight));
+ ret = dsi_set_packet(cmd, 2);
+ if (ret)
+ return ret;
+ pr_err("#%s, %d, backlight:0x%x 0x%x\n", __func__, __LINE__, cmd[2], cmd[3]);
+ return 0;
+}
+
+int dsi_get_cabc(struct r63306_cabc *cabc)
+{
+ u8 cmd[DSI_CMD_LEN];
+ int ret;
+
+ memset(cmd, 0, DSI_CMD_LEN);
+ memcpy(cmd, read_cabc_ctrl, sizeof(read_cabc_ctrl));
+ ret = dsi_set_packet(cmd, 1);
+ if (ret)
+ return ret;
+ cabc->cabc_on = (cmd[2] & (1 << 0)) ? 1 : 0;
+ cabc->pwm_on = (cmd[2] & (1 << 1)) ? 1 : 0;
+ cabc->pfm_on = (cmd[2] & (1 << 2)) ? 1 : 0;
+ cabc->ledpwm_pin = (cmd[2] & (1 << 3)) ? 1 : 0;
+ cabc->ledpwm_pol = (cmd[2] & (1 << 4)) ? 1 : 0;
+ pr_err("#%s, %d, cabc:%d, pwm_on:%d, pfm_on:%d, ledpwm_pin:%d, ledpwm_pol:%d\n",
+ __func__, __LINE__, cabc->cabc_on, cabc->pwm_on, cabc->pfm_on, cabc->ledpwm_pin, cabc->ledpwm_pol);
+ return 0;
+}
+EXPORT_SYMBOL(dsi_get_cabc);
+
+int dsi_set_cabc(struct r63306_cabc *cabc)
+{
+ u8 cmd[DSI_CMD_LEN];
+
+ memset(cmd, 0, DSI_CMD_LEN);
+ memcpy(cmd, write_cabc_ctrl, sizeof(write_cabc_ctrl));
+ cmd[2] = (cabc->cabc_on << 0) | (cabc->pwm_on << 1) |
+ (cabc->pfm_on << 2) | (cabc->ledpwm_pin << 3) |
+ (cabc->ledpwm_pol << 4);
+ return dsi_set_packet(cmd, 1 + 1);
+}
+EXPORT_SYMBOL(dsi_set_cabc);
+
+int dsi_get_cabc_param(struct r63306_cabc_param *cabc)
+{
+ u8 cmd[DSI_CMD_LEN];
+ int ret;
+
+ memset(cmd, 0, DSI_CMD_LEN);
+ memcpy(cmd, read_cabc_param, sizeof(read_cabc_param));
+ ret = dsi_set_packet(cmd, 8);
+ if (ret < 0)
+ return ret;
+#if 0
+ cabc->backlight = ((cmd[2] & 0xf) << 4) | (cmd[3] & 0xf);
+#else
+ cabc->backlight = (cmd[2] << 8) | (cmd[3] & 0xf);
+#endif
+ pr_err("#%s, %d, [2]:0x%x, [3]:0x%x, [4]:0x%x\n",
+ __func__, __LINE__, cmd[2], cmd[3], cmd[4]);
+ return 0;
+}
+EXPORT_SYMBOL(dsi_get_cabc_param);
+
+int dsi_set_cabc_param(struct r63306_cabc_param *cabc)
+{
+ u8 cmd[DSI_CMD_LEN];
+
+ memset(cmd, 0, DSI_CMD_LEN);
+ memcpy(cmd, write_cabc_param, sizeof(write_cabc_param));
+/*
+#if 0
+ cmd[2] = (cabc->backlight >> 4) & 0xf;
+ cmd[3] = cabc->backlight & 0xf;
+ cmd[4] = 0x02;
+ cmd[5] = 0x02;
+ cmd[6] = 0x04;
+ cmd[7] = 0x04;
+ cmd[8] = 0x00;
+ cmd[9] = 0x5d;
+#else
+ cmd[2] = (cabc->backlight & 0xff0) >> 4;
+ cmd[3] = cabc->backlight & 0xf;
+#endif
+*/
+ cmd[2] = cabc->backlight;
+ cmd[3] = cabc->backlight & 0xf;
+ return dsi_set_packet(cmd, 2 + 1);
+}
+
+int dsi_get_pwm(struct r63306_pwm *pwm)
+{
+ u8 cmd[DSI_CMD_LEN];
+ int ret;
+ int i;
+
+ memset(cmd, 0, DSI_CMD_LEN);
+ memcpy(cmd, read_pfm_pwm_ctrl, sizeof(read_pfm_pwm_ctrl));
+ ret = dsi_set_packet(cmd, 12);
+ if (ret)
+ return ret;
+ pwm->divider = cmd[2];
+ pwm->duty_cycle = ((cmd[3] << 8) | cmd[4]) & 0x1ff;
+ pwm->pwm_wm = (cmd[3] & 0x10) ? 1 : 0;
+#if 1
+ pr_err("#%s, %d, divider:%d, duty_cycle:%d, pwm_wm:%d\n",
+ __func__, __LINE__, pwm->divider, pwm->duty_cycle, pwm->pwm_wm);
+ for (i = 0; i < 12; i++) {
+ pr_err("c[%d]:0x%x ", i, cmd[i]);
+ }
+ pr_err("\n");
+#endif
+ return 0;
+}
+EXPORT_SYMBOL(dsi_get_pwm);
+
+int dsi_set_pwm(struct r63306_pwm *pwm)
+{
+#if 1
+ u8 cmd[DSI_CMD_LEN];
+
+ memset(cmd, 0, DSI_CMD_LEN);
+ memcpy(cmd, write_pfm_pwm_ctrl, sizeof(write_pfm_pwm_ctrl));
+ cmd[2] = pwm->divider;
+ cmd[3] = ((pwm->duty_cycle & 0x100) >> 8) | (pwm->pwm_wm << 4);
+ cmd[4] = pwm->duty_cycle & 0xff;
+ //cmd[4] = 0x0e;
+ return dsi_set_packet(cmd, 12 + 1);
+#else
+ u8 cmd[DSI_CMD_LEN];
+ int ret;
+
+ memset(cmd, 0, DSI_CMD_LEN);
+ memcpy(cmd, read_pfm_pwm_ctrl, sizeof(read_pfm_pwm_ctrl));
+ ret = dsi_set_packet(cmd, 12);
+ if (ret)
+ return ret;
+ cmd[0] = write_pfm_pwm_ctrl[0];
+ cmd[2] = pwm->divider;
+ cmd[3] = ((pwm->duty_cycle & 0x100) >> 8) | (pwm->pwm_wm << 4);
+ cmd[3] |= (1 << 4);
+ cmd[4] = pwm->duty_cycle & 0xff;
+ //cmd[4] = 0x0e;
+ cmd[5] = 0x73;
+ return dsi_set_packet(cmd, 12 + 1);
+#endif
+}
+EXPORT_SYMBOL(dsi_set_pwm);
+
+static int r63306_probe(struct platform_device *pdev)
+{
+ struct r63306_chip *chip;
+ struct r63306_device_id id;
+ struct r63306_cabc cabc;
+ int ret;
+
+ if (dsi_get_id(&id) < 0 || id.vendor != RENESAS_ID_VENDOR) {
+ dev_err(&pdev->dev, "Can't detect Renesas chip\n");
+ return -EPROBE_DEFER;
+ }
+
+ /* set pwm on */
+ ret = dsi_get_cabc(&cabc);
+ if (ret < 0)
+ return -EPROBE_DEFER;
+ //cabc.pwm_on = true;
+ ret = dsi_set_cabc(&cabc);
+ if (ret < 0)
+ return -EPROBE_DEFER;
+ chip = kzalloc(sizeof(struct r63306_chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+ chip->dev = &pdev->dev;
+
+ ret = mfd_add_devices(chip->dev, 0, pwm_devs, ARRAY_SIZE(pwm_devs),
+ NULL, 0, NULL);
+ if (ret)
+ goto err;
+ return 0;
+err:
+ kfree(chip);
+ return ret;
+}
+
+static int r63306_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static const struct of_device_id r63306_of_match[] = {
+ { .compatible = "renesas,r63306", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, r63306_of_match);
+
+static struct platform_driver r63306_driver = {
+ .probe = r63306_probe,
+ .remove = r63306_remove,
+ .driver = {
+ .name = "r63306",
+ .owner = THIS_MODULE,
+ .of_match_table = r63306_of_match,
+ },
+};
+module_platform_driver(r63306_driver);
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 4f98f8b38395..41e8f8770ea2 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -34,6 +34,7 @@
#include <linux/delay.h>
#include <linux/capability.h>
#include <linux/compat.h>
+#include <linux/pm_runtime.h>
#define CREATE_TRACE_POINTS
#include <trace/events/mmc.h>
@@ -221,7 +222,7 @@ static ssize_t power_ro_lock_store(struct device *dev,
md = mmc_blk_get(dev_to_disk(dev));
card = md->queue.card;
- mmc_claim_host(card->host);
+ mmc_get_card(card);
ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP,
card->ext_csd.boot_ro_lock |
@@ -232,7 +233,7 @@ static ssize_t power_ro_lock_store(struct device *dev,
else
card->ext_csd.boot_ro_lock |= EXT_CSD_BOOT_WP_B_PWR_WP_EN;
- mmc_release_host(card->host);
+ mmc_put_card(card);
if (!ret) {
pr_info("%s: Locking boot partition ro until next power on\n",
@@ -490,7 +491,7 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
mrq.cmd = &cmd;
- mmc_claim_host(card->host);
+ mmc_get_card(card);
err = mmc_blk_part_switch(card, md);
if (err)
@@ -557,7 +558,7 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
}
cmd_rel_host:
- mmc_release_host(card->host);
+ mmc_put_card(card);
cmd_done:
mmc_blk_put(md);
@@ -1945,7 +1946,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
if (req && !mq->mqrq_prev->req)
/* claim host only for the first request */
- mmc_claim_host(card->host);
+ mmc_get_card(card);
ret = mmc_blk_part_switch(card, md);
if (ret) {
@@ -1989,7 +1990,7 @@ out:
* In case sepecial request, there is no reentry to
* the 'mmc_blk_issue_rq' with 'mqrq_prev->req'.
*/
- mmc_release_host(card->host);
+ mmc_put_card(card);
return ret;
}
@@ -2390,6 +2391,19 @@ static int mmc_blk_probe(struct mmc_card *card)
if (mmc_add_disk(part_md))
goto out;
}
+
+ pm_runtime_set_autosuspend_delay(&card->dev, 3000);
+ pm_runtime_use_autosuspend(&card->dev);
+
+ /*
+ * Don't enable runtime PM for SD-combo cards here. Leave that
+ * decision to be taken during the SDIO init sequence instead.
+ */
+ if (card->type != MMC_TYPE_SD_COMBO) {
+ pm_runtime_set_active(&card->dev);
+ pm_runtime_enable(&card->dev);
+ }
+
return 0;
out:
@@ -2403,9 +2417,13 @@ static void mmc_blk_remove(struct mmc_card *card)
struct mmc_blk_data *md = mmc_get_drvdata(card);
mmc_blk_remove_parts(card, md);
+ pm_runtime_get_sync(&card->dev);
mmc_claim_host(card->host);
mmc_blk_part_switch(card, md);
mmc_release_host(card->host);
+ if (card->type != MMC_TYPE_SD_COMBO)
+ pm_runtime_disable(&card->dev);
+ pm_runtime_put_noidle(&card->dev);
mmc_blk_remove_req(md);
mmc_set_drvdata(card, NULL);
#ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME
@@ -2420,6 +2438,7 @@ static int mmc_blk_suspend(struct mmc_card *card)
struct mmc_blk_data *md = mmc_get_drvdata(card);
if (md) {
+ pm_runtime_get_sync(&card->dev);
mmc_queue_suspend(&md->queue);
list_for_each_entry(part_md, &md->part, part) {
mmc_queue_suspend(&part_md->queue);
@@ -2443,6 +2462,7 @@ static int mmc_blk_resume(struct mmc_card *card)
list_for_each_entry(part_md, &md->part, part) {
mmc_queue_resume(&part_md->queue);
}
+ pm_runtime_put(&card->dev);
}
return 0;
}
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index e219c97a02a4..d9e8c2b7f4c5 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -151,15 +151,25 @@ static int mmc_bus_resume(struct device *dev)
static int mmc_runtime_suspend(struct device *dev)
{
struct mmc_card *card = mmc_dev_to_card(dev);
+ struct mmc_host *host = card->host;
+ int ret = 0;
+
+ if (host->bus_ops->runtime_suspend)
+ ret = host->bus_ops->runtime_suspend(host);
- return mmc_power_save_host(card->host);
+ return ret;
}
static int mmc_runtime_resume(struct device *dev)
{
struct mmc_card *card = mmc_dev_to_card(dev);
+ struct mmc_host *host = card->host;
+ int ret = 0;
+
+ if (host->bus_ops->runtime_resume)
+ ret = host->bus_ops->runtime_resume(host);
- return mmc_power_restore_host(card->host);
+ return ret;
}
static int mmc_runtime_idle(struct device *dev)
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 6a83f4ccc108..8fc40d004974 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -960,6 +960,29 @@ void mmc_release_host(struct mmc_host *host)
EXPORT_SYMBOL(mmc_release_host);
/*
+ * This is a helper function, which fetches a runtime pm reference for the
+ * card device and also claims the host.
+ */
+void mmc_get_card(struct mmc_card *card)
+{
+ pm_runtime_get_sync(&card->dev);
+ mmc_claim_host(card->host);
+}
+EXPORT_SYMBOL(mmc_get_card);
+
+/*
+ * This is a helper function, which releases the host and drops the runtime
+ * pm reference for the card device.
+ */
+void mmc_put_card(struct mmc_card *card)
+{
+ mmc_release_host(card->host);
+ pm_runtime_mark_last_busy(&card->dev);
+ pm_runtime_put_autosuspend(&card->dev);
+}
+EXPORT_SYMBOL(mmc_put_card);
+
+/*
* Internal function that does the actual ios call to the host driver,
* optionally printing some debug output.
*/
@@ -1467,7 +1490,7 @@ void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type)
* If a host does all the power sequencing itself, ignore the
* initial MMC_POWER_UP stage.
*/
-static void mmc_power_up(struct mmc_host *host)
+void mmc_power_up(struct mmc_host *host)
{
int bit;
@@ -2700,14 +2723,8 @@ int mmc_suspend_host(struct mmc_host *host)
mmc_bus_get(host);
if (host->bus_ops && !host->bus_dead) {
- if (host->bus_ops->suspend) {
- if (mmc_card_doing_bkops(host->card)) {
- err = mmc_stop_bkops(host->card);
- if (err)
- goto out;
- }
+ if (host->bus_ops->suspend)
err = host->bus_ops->suspend(host);
- }
if (err == -ENOSYS || !host->bus_ops->resume) {
/*
@@ -2731,10 +2748,8 @@ int mmc_suspend_host(struct mmc_host *host)
if (!err && !mmc_card_keep_power(host))
mmc_power_off(host);
-out:
return err;
}
-
EXPORT_SYMBOL(mmc_suspend_host);
/**
@@ -2795,22 +2810,10 @@ int mmc_pm_notify(struct notifier_block *notify_block,
struct mmc_host *host = container_of(
notify_block, struct mmc_host, pm_notify);
unsigned long flags;
- int err = 0;
switch (mode) {
case PM_HIBERNATION_PREPARE:
case PM_SUSPEND_PREPARE:
- if (host->card && mmc_card_mmc(host->card) &&
- mmc_card_doing_bkops(host->card)) {
- err = mmc_stop_bkops(host->card);
- if (err) {
- pr_err("%s: didn't stop bkops\n",
- mmc_hostname(host));
- return err;
- }
- mmc_card_clr_doing_bkops(host->card);
- }
-
spin_lock_irqsave(&host->lock, flags);
if (mmc_bus_needs_resume(host)) {
spin_unlock_irqrestore(&host->lock, flags);
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index b9f18a2a8874..6242ffb789c4 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -22,6 +22,8 @@ struct mmc_bus_ops {
void (*detect)(struct mmc_host *);
int (*suspend)(struct mmc_host *);
int (*resume)(struct mmc_host *);
+ int (*runtime_suspend)(struct mmc_host *);
+ int (*runtime_resume)(struct mmc_host *);
int (*power_save)(struct mmc_host *);
int (*power_restore)(struct mmc_host *);
int (*alive)(struct mmc_host *);
@@ -44,6 +46,7 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage);
int __mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage);
void mmc_set_timing(struct mmc_host *host, unsigned int timing);
void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type);
+void mmc_power_up(struct mmc_host *host);
void mmc_power_off(struct mmc_host *host);
void mmc_power_cycle(struct mmc_host *host);
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 35c2f85b1956..54829c0ed000 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -258,13 +258,13 @@ static int mmc_dbg_card_status_get(void *data, u64 *val)
u32 status;
int ret;
- mmc_claim_host(card->host);
+ mmc_get_card(card);
ret = mmc_send_status(data, &status);
if (!ret)
*val = status;
- mmc_release_host(card->host);
+ mmc_put_card(card);
return ret;
}
@@ -291,9 +291,9 @@ static int mmc_ext_csd_open(struct inode *inode, struct file *filp)
goto out_free;
}
- mmc_claim_host(card->host);
+ mmc_get_card(card);
err = mmc_send_ext_csd(card, ext_csd);
- mmc_release_host(card->host);
+ mmc_put_card(card);
if (err)
goto out_free;
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 0cbd1effe960..506f4ee84e12 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1380,14 +1380,14 @@ static void mmc_detect(struct mmc_host *host)
BUG_ON(!host);
BUG_ON(!host->card);
- mmc_claim_host(host);
+ mmc_get_card(host->card);
/*
* Just check if our card has been removed.
*/
err = _mmc_detect_card_removed(host);
- mmc_release_host(host);
+ mmc_put_card(host->card);
if (err) {
mmc_remove(host);
@@ -1411,6 +1411,12 @@ static int mmc_suspend(struct mmc_host *host)
mmc_claim_host(host);
+ if (mmc_card_doing_bkops(host->card)) {
+ err = mmc_stop_bkops(host->card);
+ if (err)
+ goto out;
+ }
+
err = mmc_cache_ctrl(host, 0);
if (err)
goto out;
@@ -1448,6 +1454,54 @@ static int mmc_resume(struct mmc_host *host)
return err;
}
+
+/*
+ * Callback for runtime_suspend.
+ */
+static int mmc_runtime_suspend(struct mmc_host *host)
+{
+ int err;
+
+ if (!(host->caps & MMC_CAP_AGGRESSIVE_PM))
+ return 0;
+
+ mmc_claim_host(host);
+
+ err = mmc_suspend(host);
+ if (err) {
+ pr_err("%s: error %d doing aggessive suspend\n",
+ mmc_hostname(host), err);
+ goto out;
+ }
+ mmc_power_off(host);
+
+out:
+ mmc_release_host(host);
+ return err;
+}
+
+/*
+ * Callback for runtime_resume.
+ */
+static int mmc_runtime_resume(struct mmc_host *host)
+{
+ int err;
+
+ if (!(host->caps & MMC_CAP_AGGRESSIVE_PM))
+ return 0;
+
+ mmc_claim_host(host);
+
+ mmc_power_up(host);
+ err = mmc_resume(host);
+ if (err)
+ pr_err("%s: error %d doing aggessive resume\n",
+ mmc_hostname(host), err);
+
+ mmc_release_host(host);
+ return 0;
+}
+
static int mmc_power_restore(struct mmc_host *host)
{
int ret;
@@ -1508,6 +1562,8 @@ static const struct mmc_bus_ops mmc_ops_unsafe = {
.detect = mmc_detect,
.suspend = mmc_suspend,
.resume = mmc_resume,
+ .runtime_suspend = mmc_runtime_suspend,
+ .runtime_resume = mmc_runtime_resume,
.power_restore = mmc_power_restore,
.alive = mmc_alive,
};
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index f008318c5c4d..09fc0f26236e 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -1062,7 +1062,7 @@ static void mmc_sd_detect(struct mmc_host *host)
BUG_ON(!host);
BUG_ON(!host->card);
- mmc_claim_host(host);
+ mmc_get_card(host->card);
/*
* Just check if our card has been removed.
@@ -1085,7 +1085,7 @@ static void mmc_sd_detect(struct mmc_host *host)
err = _mmc_detect_card_removed(host);
#endif
- mmc_release_host(host);
+ mmc_put_card(host->card);
if (err) {
mmc_sd_remove(host);
@@ -1155,6 +1155,53 @@ static int mmc_sd_resume(struct mmc_host *host)
return err;
}
+/*
+ * Callback for runtime_suspend.
+ */
+static int mmc_sd_runtime_suspend(struct mmc_host *host)
+{
+ int err;
+
+ if (!(host->caps & MMC_CAP_AGGRESSIVE_PM))
+ return 0;
+
+ mmc_claim_host(host);
+
+ err = mmc_sd_suspend(host);
+ if (err) {
+ pr_err("%s: error %d doing aggessive suspend\n",
+ mmc_hostname(host), err);
+ goto out;
+ }
+ mmc_power_off(host);
+
+out:
+ mmc_release_host(host);
+ return err;
+}
+
+/*
+ * Callback for runtime_resume.
+ */
+static int mmc_sd_runtime_resume(struct mmc_host *host)
+{
+ int err;
+
+ if (!(host->caps & MMC_CAP_AGGRESSIVE_PM))
+ return 0;
+
+ mmc_claim_host(host);
+
+ mmc_power_up(host);
+ err = mmc_sd_resume(host);
+ if (err)
+ pr_err("%s: error %d doing aggessive resume\n",
+ mmc_hostname(host), err);
+
+ mmc_release_host(host);
+ return 0;
+}
+
static int mmc_sd_power_restore(struct mmc_host *host)
{
int ret;
@@ -1179,6 +1226,8 @@ static const struct mmc_bus_ops mmc_sd_ops = {
static const struct mmc_bus_ops mmc_sd_ops_unsafe = {
.remove = mmc_sd_remove,
.detect = mmc_sd_detect,
+ .runtime_suspend = mmc_sd_runtime_suspend,
+ .runtime_resume = mmc_sd_runtime_resume,
.suspend = mmc_sd_suspend,
.resume = mmc_sd_resume,
.power_restore = mmc_sd_power_restore,
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 46e68f125ff2..33831c4b2f2b 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -1072,11 +1072,27 @@ out:
return ret;
}
+static int mmc_sdio_runtime_suspend(struct mmc_host *host)
+{
+ /* No references to the card, cut the power to it. */
+ mmc_power_off(host);
+ return 0;
+}
+
+static int mmc_sdio_runtime_resume(struct mmc_host *host)
+{
+ /* Restore power and re-initialize. */
+ mmc_power_up(host);
+ return mmc_sdio_power_restore(host);
+}
+
static const struct mmc_bus_ops mmc_sdio_ops = {
.remove = mmc_sdio_remove,
.detect = mmc_sdio_detect,
.suspend = mmc_sdio_suspend,
.resume = mmc_sdio_resume,
+ .runtime_suspend = mmc_sdio_runtime_suspend,
+ .runtime_resume = mmc_sdio_runtime_resume,
.power_restore = mmc_sdio_power_restore,
.alive = mmc_sdio_alive,
};
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 9ab8f8dee942..9652fd646b37 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -556,6 +556,16 @@ config MMC_DW_EXYNOS
Synopsys DesignWare Memory Card Interface driver. Select this option
for platforms based on Exynos4 and Exynos5 SoC's.
+config MMC_DW_HISILICON
+ tristate "Hisilicon specific extensions for Synopsys DW Memory Card Interface"
+ depends on MMC_DW
+ select MMC_DW_PLTFM
+ select MMC_DW_IDMAC
+ help
+ This selects support for Samsung Exynos SoC specific extensions to the
+ Synopsys DesignWare Memory Card Interface driver. Select this option
+ for platforms based on Exynos4 and Exynos5 SoC's.
+
config MMC_DW_PCI
tristate "Synopsys Designware MCI support on PCI bus"
depends on MMC_DW && PCI
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index cd3228075553..38c50c00d236 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -42,6 +42,7 @@ obj-$(CONFIG_SDH_BFIN) += bfin_sdh.o
obj-$(CONFIG_MMC_DW) += dw_mmc.o
obj-$(CONFIG_MMC_DW_PLTFM) += dw_mmc-pltfm.o
obj-$(CONFIG_MMC_DW_EXYNOS) += dw_mmc-exynos.o
+obj-$(CONFIG_MMC_DW_HISILICON) += dw_mmc-hisilicon.o
obj-$(CONFIG_MMC_DW_PCI) += dw_mmc-pci.o
obj-$(CONFIG_MMC_SH_MMCIF) += sh_mmcif.o
obj-$(CONFIG_MMC_JZ4740) += jz4740_mmc.o
diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c
index f013e7e3746b..939302ee5182 100644
--- a/drivers/mmc/host/dw_mmc-exynos.c
+++ b/drivers/mmc/host/dw_mmc-exynos.c
@@ -191,7 +191,7 @@ static int dw_mci_exynos_probe(struct platform_device *pdev)
static struct platform_driver dw_mci_exynos_pltfm_driver = {
.probe = dw_mci_exynos_probe,
- .remove = __exit_p(dw_mci_pltfm_remove),
+ .remove = dw_mci_pltfm_remove,
.driver = {
.name = "dwmmc_exynos",
.of_match_table = dw_mci_exynos_match,
diff --git a/drivers/mmc/host/dw_mmc-hisilicon.c b/drivers/mmc/host/dw_mmc-hisilicon.c
new file mode 100644
index 000000000000..50ba8eb81f2b
--- /dev/null
+++ b/drivers/mmc/host/dw_mmc-hisilicon.c
@@ -0,0 +1,395 @@
+/*
+ * Copyright (c) 2013 Linaro Ltd.
+ * Copyright (c) 2013 Hisilicon Limited.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/dw_mmc.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/of_address.h>
+
+#include "dw_mmc.h"
+#include "dw_mmc-pltfm.h"
+
+#define DRIVER_NAME "dwmmc_hs"
+
+enum dw_mci_hisilicon_type {
+ DW_MCI_TYPE_HI4511,
+ DW_MCI_TYPE_HI3620,
+};
+
+static struct dw_mci_exynos_compatible {
+ char *compatible;
+ enum dw_mci_hisilicon_type type;
+} hs_compat[] = {
+ {
+ .compatible = "hisilicon,hi4511-dw-mshc",
+ .type = DW_MCI_TYPE_HI4511,
+ }, {
+ .compatible = "hisilicon,hi3620-dw-mshc",
+ .type = DW_MCI_TYPE_HI3620,
+ },
+};
+
+struct dw_mci_hs_priv_data {
+ int id;
+ int old_timing;
+ int gpio_cd;
+ enum dw_mci_hisilicon_type type;
+};
+
+static void __iomem *pctrl;
+static DEFINE_SPINLOCK(mmc_tuning_lock);
+static int hs_tuning_config[][8][6] = {
+ /* bus_clk, div, drv_sel, sam_sel_max, sam_sel_min, input_clk */
+ {
+ {180000000, 6, 6, 13, 13, 25000000}, /* 0: LEGACY 400k */
+ {0}, /* 1: MMC_HS */
+ {360000000, 6, 4, 2, 0, 50000000 }, /* 2: SD_HS */
+ {180000000, 6, 4, 13, 13, 25000000}, /* 3: SDR12 */
+ {360000000, 6, 4, 2, 0, 50000000 }, /* 4: SDR25 */
+ {720000000, 6, 1, 9, 4, 100000000 }, /* 5: SDR50 */
+ {0}, /* 6: SDR104 */
+ {360000000, 7, 1, 3, 0, 50000000 }, /* 7: DDR50 */
+ }, {
+ {26000000, 1, 1, 3, 3, 13000000 }, /* 0: LEGACY 400k */
+ {360000000, 6, 3, 3, 1, 50000000 }, /* 1: MMC_HS*/
+ {0}, /* 2: SD_HS */
+ {0}, /* 3: SDR12 */
+ {26000000, 1, 1, 3, 3, 13000000 }, /* 4: SDR25 */
+ {360000000, 6, 3, 3, 1, 50000000 }, /* 5: SDR50 */
+ {0}, /* 6: SDR104 */
+ {720000000, 6, 4, 8, 4, 100000000}, /* 7: DDR50 */
+ },
+};
+
+static void dw_mci_hs_set_timing(int idx, int sam, int drv, int div)
+{
+ unsigned int clken_reg;
+ unsigned int clken_bit;
+ unsigned int sam_sel_reg;
+ unsigned int sam_sel_bit;
+ unsigned int drv_sel_reg;
+ unsigned int drv_sel_bit;
+ unsigned int div_reg;
+ unsigned int div_bit;
+ int i = 0;
+ unsigned int temp_reg;
+ unsigned long flags;
+
+ switch (idx) {
+ case 0:
+ clken_reg = 0x1F8;
+ clken_bit = 0;
+ drv_sel_reg = 0x1F8;
+ drv_sel_bit = 4;
+ sam_sel_reg = 0x1F8;
+ sam_sel_bit = 8;
+ div_reg = 0x1F8;
+ div_bit = 1;
+ break;
+ case 1:
+ clken_reg = 0x1F8;
+ clken_bit = 12;
+ drv_sel_reg = 0x1F8;
+ drv_sel_bit = 16;
+ sam_sel_reg = 0x1F8;
+ sam_sel_bit = 20;
+ div_reg = 0x1F8;
+ div_bit = 13;
+ break;
+ case 2:
+ clken_reg = 0x1F8;
+ clken_bit = 24;
+ drv_sel_reg = 0x1F8;
+ drv_sel_bit = 28;
+ sam_sel_reg = 0x1FC;
+ sam_sel_bit = 0;
+ div_reg = 0x1F8;
+ div_bit = 25;
+ break;
+ case 3:
+ clken_reg = 0x1FC;
+ clken_bit = 4;
+ drv_sel_reg = 0x1FC;
+ drv_sel_bit = 8;
+ sam_sel_reg = 0x1FC;
+ sam_sel_bit = 12;
+ div_reg = 0x1FC;
+ div_bit = 5;
+ break;
+ default:
+ return;
+ }
+
+ spin_lock_irqsave(&mmc_tuning_lock, flags);
+
+ /* disable clock */
+ temp_reg = readl(pctrl + clken_reg);
+ temp_reg &= ~(1<<clken_bit);
+ writel(temp_reg, pctrl + clken_reg);
+
+ temp_reg = readl(pctrl + sam_sel_reg);
+ if (sam >= 0) {
+ /* set sam delay */
+ for (i = 0; i < 4; i++) {
+ if (sam % 2)
+ temp_reg |= 1<<(sam_sel_bit + i);
+ else
+ temp_reg &= ~(1<<(sam_sel_bit + i));
+ sam = sam >> 1;
+ }
+ }
+ writel(temp_reg, pctrl + sam_sel_reg);
+
+ temp_reg = readl(pctrl + drv_sel_reg);
+ if (drv >= 0) {
+ /* set drv delay */
+ for (i = 0; i < 4; i++) {
+ if (drv % 2)
+ temp_reg |= 1<<(drv_sel_bit + i);
+ else
+ temp_reg &= ~(1<<(drv_sel_bit + i));
+ drv = drv >> 1;
+ }
+ }
+ writel(temp_reg, pctrl + drv_sel_reg);
+
+ temp_reg = readl(pctrl + drv_sel_reg);
+ if (div >= 0) {
+ /* set drv delay */
+ for (i = 0; i < 3; i++) {
+ if (div % 2)
+ temp_reg |= 1<<(div_bit + i);
+ else
+ temp_reg &= ~(1<<(div_bit + i));
+ div = div >> 1;
+ }
+ }
+ writel(temp_reg, pctrl + drv_sel_reg);
+
+ /* enable clock */
+ temp_reg = readl(pctrl + clken_reg);
+ temp_reg |= 1<<clken_bit;
+ writel(temp_reg, pctrl + clken_reg);
+
+ spin_unlock_irqrestore(&mmc_tuning_lock, flags);
+}
+
+static void dw_mci_hs_tun(struct dw_mci *host, int id, int index)
+{
+ struct dw_mci_hs_priv_data *priv = host->priv;
+ int ret;
+
+ if (!pctrl)
+ return;
+
+ if (priv->old_timing == index)
+ return;
+
+ ret = clk_set_rate(host->ciu_clk, hs_tuning_config[id][index][0]);
+ if (ret)
+ dev_err(host->dev, "clk_set_rate failed\n");
+
+ dw_mci_hs_set_timing(id,
+ (hs_tuning_config[id][index][3] +
+ hs_tuning_config[id][index][4]) / 2,
+ hs_tuning_config[id][index][2],
+ hs_tuning_config[id][index][1]);
+
+ host->bus_hz = hs_tuning_config[id][index][5];
+ priv->old_timing = index;
+}
+
+static void dw_mci_hs_set_ios(struct dw_mci *host, struct mmc_ios *ios)
+{
+ struct dw_mci_hs_priv_data *priv = host->priv;
+ int id = priv->id;
+
+ if (priv->type == DW_MCI_TYPE_HI4511)
+ dw_mci_hs_tun(host, id, ios->timing);
+}
+
+static int dw_mci_hs_priv_init(struct dw_mci *host)
+{
+ struct dw_mci_hs_priv_data *priv;
+ int i;
+
+ priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv) {
+ dev_err(host->dev, "mem alloc failed for private data\n");
+ return -ENOMEM;
+ }
+ priv->id = of_alias_get_id(host->dev->of_node, "mshc");
+ priv->old_timing = -1;
+ host->priv = priv;
+
+ for (i = 0; i < ARRAY_SIZE(hs_compat); i++) {
+ if (of_device_is_compatible(host->dev->of_node,
+ hs_compat[i].compatible))
+ priv->type = hs_compat[i].type;
+ }
+
+ if (priv->type == DW_MCI_TYPE_HI4511) {
+ if (!pctrl) {
+ struct device_node *node;
+
+ node = of_find_compatible_node(NULL, NULL,
+ "hisilicon,pctrl");
+ pctrl = of_iomap(node, 0);
+ }
+ }
+
+ return 0;
+}
+
+static int dw_mci_hs_setup_clock(struct dw_mci *host)
+{
+ struct dw_mci_hs_priv_data *priv = host->priv;
+
+ if (priv->type == DW_MCI_TYPE_HI4511)
+ dw_mci_hs_tun(host, priv->id, 0);
+
+ return 0;
+}
+
+
+static irqreturn_t dw_mci_hs_card_detect(int irq, void *data)
+{
+ struct dw_mci *host = (struct dw_mci *)data;
+
+ queue_work(host->card_workqueue, &host->card_work);
+ return IRQ_HANDLED;
+};
+
+static int dw_mci_hs_get_cd(struct dw_mci *host, u32 slot_id)
+{
+ unsigned int status;
+ struct dw_mci_hs_priv_data *priv = host->priv;
+
+ status = !gpio_get_value(priv->gpio_cd);
+ return status;
+}
+
+static unsigned long hs_dwmmc_caps[4] = {
+ MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED,
+ MMC_CAP_8_BIT_DATA | MMC_CAP_MMC_HIGHSPEED,
+ 0,
+ 0,
+};
+
+static const struct dw_mci_drv_data hs_drv_data = {
+ .caps = hs_dwmmc_caps,
+ .init = dw_mci_hs_priv_init,
+ .set_ios = dw_mci_hs_set_ios,
+ .setup_clock = dw_mci_hs_setup_clock,
+};
+
+static const struct of_device_id dw_mci_hs_match[] = {
+ { .compatible = "hisilicon,hi4511-dw-mshc",
+ .data = &hs_drv_data, },
+ { .compatible = "hisilicon,hi3620-dw-mshc",
+ .data = &hs_drv_data, },
+ {},
+};
+MODULE_DEVICE_TABLE(of, dw_mci_hs_match);
+
+int dw_mci_hs_probe(struct platform_device *pdev)
+{
+ const struct dw_mci_drv_data *drv_data;
+ const struct of_device_id *match;
+ struct dw_mci *host;
+ int gpio, err;
+
+ match = of_match_node(dw_mci_hs_match, pdev->dev.of_node);
+ drv_data = match->data;
+
+ err = dw_mci_pltfm_register(pdev, drv_data);
+ if (err)
+ return err;
+
+ host = platform_get_drvdata(pdev);
+ if (host->pdata->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION)
+ return 0;
+
+ gpio = of_get_named_gpio(pdev->dev.of_node, "cd-gpio", 0);
+ if (gpio_is_valid(gpio)) {
+ if (devm_gpio_request(host->dev, gpio, "dw-mci-cd")) {
+ dev_err(host->dev, "gpio [%d] request failed\n", gpio);
+ } else {
+ struct dw_mci_hs_priv_data *priv = host->priv;
+ priv->gpio_cd = gpio;
+ host->pdata->get_cd = dw_mci_hs_get_cd;
+ err = devm_request_irq(host->dev, gpio_to_irq(gpio),
+ dw_mci_hs_card_detect,
+ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+ DRIVER_NAME, host);
+ if (err)
+ dev_warn(mmc_dev(host->dev), "request gpio irq error\n");
+ }
+
+ } else {
+ dev_info(host->dev, "cd gpio not available");
+ }
+ return 0;
+}
+
+static int dw_mci_hs_suspend(struct device *dev)
+{
+ int ret;
+ struct dw_mci *host = dev_get_drvdata(dev);
+ struct dw_mci_hs_priv_data *priv = host->priv;
+
+ ret = dw_mci_suspend(host);
+ if (ret)
+ return ret;
+ priv->old_timing = -1;
+
+ return 0;
+}
+
+static int dw_mci_hs_resume(struct device *dev)
+{
+ int ret;
+ struct dw_mci *host = dev_get_drvdata(dev);
+ struct dw_mci_hs_priv_data *priv = host->priv;
+
+ if (priv->type == DW_MCI_TYPE_HI4511) {
+ int id = priv->id;
+
+ dw_mci_hs_tun(host, id, MMC_TIMING_LEGACY);
+ }
+
+ ret = dw_mci_resume(host);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+SIMPLE_DEV_PM_OPS(dw_mci_hs_pmops, dw_mci_hs_suspend, dw_mci_hs_resume);
+
+static struct platform_driver dw_mci_hs_pltfm_driver = {
+ .probe = dw_mci_hs_probe,
+ .remove = dw_mci_pltfm_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ .of_match_table = of_match_ptr(dw_mci_hs_match),
+ .pm = &dw_mci_hs_pmops,
+ },
+};
+
+module_platform_driver(dw_mci_hs_pltfm_driver);
+
+MODULE_DESCRIPTION("Hisilicon Specific DW-MSHC Driver Extension");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
index 41c27b74b003..c58e513185d4 100644
--- a/drivers/mmc/host/dw_mmc-pltfm.c
+++ b/drivers/mmc/host/dw_mmc-pltfm.c
@@ -68,7 +68,7 @@ static int dw_mci_pltfm_probe(struct platform_device *pdev)
return dw_mci_pltfm_register(pdev, NULL);
}
-static int dw_mci_pltfm_remove(struct platform_device *pdev)
+int dw_mci_pltfm_remove(struct platform_device *pdev)
{
struct dw_mci *host = platform_get_drvdata(pdev);
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index bc3a1bc4940f..78166a0f5fc8 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -871,7 +871,7 @@ static int dw_mci_get_cd(struct mmc_host *mmc)
if (brd->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION)
present = 1;
else if (brd->get_cd)
- present = !brd->get_cd(slot->id);
+ present = !brd->get_cd(slot->host, slot->id);
else
present = (mci_readl(slot->host, CDETECT) & (1 << slot->id))
== 0 ? 1 : 0;
@@ -933,6 +933,45 @@ static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb)
}
}
+static int dw_mci_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+ struct dw_mci_slot *slot = mmc_priv(mmc);
+ struct dw_mci *host = slot->host;
+ int min_uV = 0, max_uV = 0;
+ int ret;
+
+ if (!host->vqmmc)
+ return 0;
+
+ switch (ios->signal_voltage) {
+ case MMC_SIGNAL_VOLTAGE_330:
+ min_uV = 2700000;
+ max_uV = 3600000;
+ break;
+ case MMC_SIGNAL_VOLTAGE_180:
+ min_uV = 1700000;
+ max_uV = 1950000;
+ break;
+ case MMC_SIGNAL_VOLTAGE_120:
+ min_uV = 1100000;
+ max_uV = 1300000;
+ break;
+ default:
+ return 0;
+ }
+
+ ret = regulator_set_voltage(host->vqmmc, min_uV, max_uV);
+ if (ret) {
+ pr_warning("%s: Switching signalling voltage "
+ " failed\n", mmc_hostname(mmc));
+ return -EIO;
+ }
+
+ /* Wait for 5ms */
+ usleep_range(5000, 5500);
+ return 0;
+}
+
static const struct mmc_host_ops dw_mci_ops = {
.request = dw_mci_request,
.pre_req = dw_mci_pre_req,
@@ -941,6 +980,7 @@ static const struct mmc_host_ops dw_mci_ops = {
.get_ro = dw_mci_get_ro,
.get_cd = dw_mci_get_cd,
.enable_sdio_irq = dw_mci_enable_sdio_irq,
+ .start_signal_voltage_switch = dw_mci_switch_voltage,
};
static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq)
@@ -1998,6 +2038,19 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
}
}
+ host->vqmmc = devm_regulator_get(mmc_dev(mmc), "vqmmc");
+ if (IS_ERR(host->vqmmc)) {
+ pr_warning("%s: no vqmmc regulator found\n", mmc_hostname(mmc));
+ host->vqmmc = NULL;
+ } else {
+ ret = regulator_enable(host->vqmmc);
+ if (ret) {
+ dev_err(host->dev,
+ "failed to enable regulator vqmmc: %d\n", ret);
+ goto err_setup_bus;
+ }
+ }
+
if (dw_mci_get_cd(mmc))
set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
else
@@ -2418,6 +2471,9 @@ void dw_mci_remove(struct dw_mci *host)
if (host->vmmc)
regulator_disable(host->vmmc);
+ if (host->vqmmc)
+ regulator_disable(host->vqmmc);
+
if (!IS_ERR(host->ciu_clk))
clk_disable_unprepare(host->ciu_clk);
@@ -2454,6 +2510,9 @@ int dw_mci_suspend(struct dw_mci *host)
if (host->vmmc)
regulator_disable(host->vmmc);
+ if (host->vqmmc)
+ regulator_disable(host->vqmmc);
+
return 0;
}
EXPORT_SYMBOL(dw_mci_suspend);
@@ -2471,6 +2530,15 @@ int dw_mci_resume(struct dw_mci *host)
}
}
+ if (host->vqmmc) {
+ ret = regulator_enable(host->vqmmc);
+ if (ret) {
+ dev_err(host->dev,
+ "failed to enable regulator vqmmc: %d\n", ret);
+ return ret;
+ }
+ }
+
if (!mci_wait_reset(host->dev, host)) {
ret = -ENODEV;
return ret;
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 8bb26446037e..08774c02a840 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -514,5 +514,12 @@ config REGULATOR_AS3711
This driver provides support for the voltage regulators on the
AS3711 PMIC
+config REGULATOR_HI6421
+ tristate "HiSilicon Hi6421 PMIC regulators"
+ depends on MFD_HI6421_PMIC
+ help
+ This driver provides support for the voltage regulators on the
+ HiSilicon Hi6421 PMU / Codec IC.
+
endif
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 47a34ff88f98..5a67225c8973 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -70,6 +70,6 @@ obj-$(CONFIG_REGULATOR_WM831X) += wm831x-ldo.o
obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o
obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o
obj-$(CONFIG_REGULATOR_WM8994) += wm8994-regulator.o
-
+obj-$(CONFIG_REGULATOR_HI6421) += hi6421-regulator.o
ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG
diff --git a/drivers/regulator/hi6421-regulator.c b/drivers/regulator/hi6421-regulator.c
new file mode 100644
index 000000000000..083e2c3d83ca
--- /dev/null
+++ b/drivers/regulator/hi6421-regulator.c
@@ -0,0 +1,560 @@
+/*
+ * Device driver for regulators in Hi6421 IC
+ *
+ * Copyright (c) 2013 Linaro Ltd.
+ * Copyright (c) 2011 Hisilicon.
+ *
+ * Guodong Xu <guodong.xu@linaro.org>
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/mfd/hi6421-pmic.h>
+#include <linux/delay.h>
+#include <linux/time.h>
+
+struct hi6421_regulator_register_info {
+ u32 ctrl_reg;
+ u32 enable_mask;
+ u32 eco_mode_mask;
+ u32 vset_reg;
+ u32 vset_mask;
+};
+
+struct hi6421_regulator {
+ const char *name;
+ struct hi6421_regulator_register_info register_info;
+ struct timeval last_off_time;
+ u32 off_on_delay;
+ u32 eco_uA;
+ struct regulator_desc rdesc;
+ int (*dt_parse)(struct hi6421_regulator *, struct platform_device *);
+};
+
+static inline struct hi6421_pmic *rdev_to_pmic(struct regulator_dev *dev)
+{
+ /* regulator_dev parent to->
+ * hi6421 regulator platform device_dev parent to->
+ * hi6421 pmic platform device_dev
+ */
+ return dev_get_drvdata(rdev_get_dev(dev)->parent->parent);
+}
+
+/* helper function to ensure when it returns it is at least 'delay_us'
+ * microseconds after 'since'.
+ */
+static void ensured_time_after(struct timeval since, u32 delay_us)
+{
+ struct timeval now;
+ u64 elapsed_ns64, delay_ns64;
+ u32 actual_us32;
+
+ delay_ns64 = delay_us * NSEC_PER_USEC;
+ do_gettimeofday(&now);
+ elapsed_ns64 = timeval_to_ns(&now) - timeval_to_ns(&since);
+ if (delay_ns64 > elapsed_ns64) {
+ actual_us32 = ((u32)(delay_ns64 - elapsed_ns64) /
+ NSEC_PER_USEC);
+ if (actual_us32 >= 1000) {
+ mdelay(actual_us32 / 1000);
+ udelay(actual_us32 % 1000);
+ } else if (actual_us32 > 0) {
+ udelay(actual_us32);
+ }
+ }
+ return;
+}
+
+static int hi6421_regulator_is_enabled(struct regulator_dev *dev)
+{
+ u32 reg_val;
+ struct hi6421_regulator *sreg = rdev_get_drvdata(dev);
+ struct hi6421_pmic *pmic = rdev_to_pmic(dev);
+
+ reg_val = hi6421_pmic_read(pmic, sreg->register_info.ctrl_reg);
+
+ return ((reg_val & sreg->register_info.enable_mask) != 0);
+}
+
+static int hi6421_regulator_enable(struct regulator_dev *dev)
+{
+ struct hi6421_regulator *sreg = rdev_get_drvdata(dev);
+ struct hi6421_pmic *pmic = rdev_to_pmic(dev);
+
+ /* keep a distance of off_on_delay from last time disabled */
+ ensured_time_after(sreg->last_off_time, sreg->off_on_delay);
+
+ /* cannot enable more than one regulator at one time */
+ mutex_lock(&pmic->enable_mutex);
+ ensured_time_after(pmic->last_enabled, HI6421_REGS_ENA_PROTECT_TIME);
+
+ /* set enable register */
+ hi6421_pmic_rmw(pmic, sreg->register_info.ctrl_reg,
+ sreg->register_info.enable_mask,
+ sreg->register_info.enable_mask);
+
+ do_gettimeofday(&pmic->last_enabled);
+ mutex_unlock(&pmic->enable_mutex);
+
+ return 0;
+}
+
+static int hi6421_regulator_disable(struct regulator_dev *dev)
+{
+ struct hi6421_regulator *sreg = rdev_get_drvdata(dev);
+ struct hi6421_pmic *pmic = rdev_to_pmic(dev);
+
+ /* set enable register to 0 */
+ hi6421_pmic_rmw(pmic, sreg->register_info.ctrl_reg,
+ sreg->register_info.enable_mask, 0);
+
+ do_gettimeofday(&sreg->last_off_time);
+
+ return 0;
+}
+
+static int hi6421_regulator_get_voltage(struct regulator_dev *dev)
+{
+ struct hi6421_regulator *sreg = rdev_get_drvdata(dev);
+ struct hi6421_pmic *pmic = rdev_to_pmic(dev);
+ u32 reg_val, selector;
+
+ /* get voltage selector */
+ reg_val = hi6421_pmic_read(pmic, sreg->register_info.vset_reg);
+ selector = (reg_val & sreg->register_info.vset_mask) >>
+ (ffs(sreg->register_info.vset_mask) - 1);
+
+ return sreg->rdesc.ops->list_voltage(dev, selector);
+}
+
+static int hi6421_regulator_ldo_set_voltage(struct regulator_dev *dev,
+ int min_uV, int max_uV, unsigned *selector)
+{
+ struct hi6421_regulator *sreg = rdev_get_drvdata(dev);
+ struct hi6421_pmic *pmic = rdev_to_pmic(dev);
+ u32 vsel;
+ int ret = 0;
+
+ for (vsel = 0; vsel < sreg->rdesc.n_voltages; vsel++) {
+ int uV = sreg->rdesc.volt_table[vsel];
+ /* Break at the first in-range value */
+ if (min_uV <= uV && uV <= max_uV)
+ break;
+ }
+
+ /* unlikely to happen. sanity test done by regulator core */
+ if (unlikely(vsel == sreg->rdesc.n_voltages))
+ return -EINVAL;
+
+ *selector = vsel;
+ /* set voltage selector */
+ hi6421_pmic_rmw(pmic, sreg->register_info.vset_reg,
+ sreg->register_info.vset_mask,
+ vsel << (ffs(sreg->register_info.vset_mask) - 1));
+
+ return ret;
+}
+
+static int hi6421_regulator_buck012_set_voltage(struct regulator_dev *dev,
+ int min_uV, int max_uV, unsigned *selector)
+{
+ struct hi6421_regulator *sreg = rdev_get_drvdata(dev);
+ struct hi6421_pmic *pmic = rdev_to_pmic(dev);
+ u32 vsel;
+ int ret = 0;
+
+ vsel = DIV_ROUND_UP((max_uV - sreg->rdesc.min_uV),
+ sreg->rdesc.uV_step);
+
+ *selector = vsel;
+ /* set voltage selector */
+ hi6421_pmic_rmw(pmic, sreg->register_info.vset_reg,
+ sreg->register_info.vset_mask,
+ vsel << (ffs(sreg->register_info.vset_mask) - 1));
+
+ return ret;
+}
+
+static unsigned int hi6421_regulator_get_mode(struct regulator_dev *dev)
+{
+ struct hi6421_regulator *sreg = rdev_get_drvdata(dev);
+ struct hi6421_pmic *pmic = rdev_to_pmic(dev);
+ u32 reg_val;
+
+ reg_val = hi6421_pmic_read(pmic, sreg->register_info.ctrl_reg);
+ if (reg_val & sreg->register_info.eco_mode_mask)
+ return REGULATOR_MODE_IDLE;
+ else
+ return REGULATOR_MODE_NORMAL;
+}
+
+static int hi6421_regulator_set_mode(struct regulator_dev *dev,
+ unsigned int mode)
+{
+ struct hi6421_regulator *sreg = rdev_get_drvdata(dev);
+ struct hi6421_pmic *pmic = rdev_to_pmic(dev);
+ u32 eco_mode;
+
+ switch (mode) {
+ case REGULATOR_MODE_NORMAL:
+ eco_mode = HI6421_ECO_MODE_DISABLE;
+ break;
+ case REGULATOR_MODE_IDLE:
+ eco_mode = HI6421_ECO_MODE_ENABLE;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* set mode */
+ hi6421_pmic_rmw(pmic, sreg->register_info.ctrl_reg,
+ sreg->register_info.eco_mode_mask,
+ eco_mode << (ffs(sreg->register_info.eco_mode_mask) - 1));
+
+ return 0;
+}
+
+
+unsigned int hi6421_regulator_get_optimum_mode(struct regulator_dev *dev,
+ int input_uV, int output_uV, int load_uA)
+{
+ struct hi6421_regulator *sreg = rdev_get_drvdata(dev);
+
+ if ((load_uA == 0) || (load_uA > sreg->eco_uA))
+ return REGULATOR_MODE_NORMAL;
+ else
+ return REGULATOR_MODE_IDLE;
+}
+
+static int hi6421_dt_parse_common(struct hi6421_regulator *sreg,
+ struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct regulator_desc *rdesc = &sreg->rdesc;
+ unsigned int register_info[3];
+ int ret = 0;
+
+ /* parse .register_info.ctrl_reg */
+ ret = of_property_read_u32_array(np, "hisilicon,hi6421-ctrl",
+ register_info, 3);
+ if (ret) {
+ dev_err(dev, "no hisilicon,hi6421-ctrl property set\n");
+ goto dt_parse_common_end;
+ }
+ sreg->register_info.ctrl_reg = register_info[0];
+ sreg->register_info.enable_mask = register_info[1];
+ sreg->register_info.eco_mode_mask = register_info[2];
+
+ /* parse .register_info.vset_reg */
+ ret = of_property_read_u32_array(np, "hisilicon,hi6421-vset",
+ register_info, 2);
+ if (ret) {
+ dev_err(dev, "no hisilicon,hi6421-vset property set\n");
+ goto dt_parse_common_end;
+ }
+ sreg->register_info.vset_reg = register_info[0];
+ sreg->register_info.vset_mask = register_info[1];
+
+ /* parse .off-on-delay */
+ ret = of_property_read_u32(np, "hisilicon,hi6421-off-on-delay-us",
+ &sreg->off_on_delay);
+ if (ret) {
+ dev_err(dev, "no hisilicon,hi6421-off-on-delay-us property set\n");
+ goto dt_parse_common_end;
+ }
+
+ /* parse .enable_time */
+ ret = of_property_read_u32(np, "hisilicon,hi6421-enable-time-us",
+ &rdesc->enable_time);
+ if (ret) {
+ dev_err(dev, "no hisilicon,hi6421-enable-time-us property set\n");
+ goto dt_parse_common_end;
+ }
+
+ /* parse .eco_uA */
+ ret = of_property_read_u32(np, "hisilicon,hi6421-eco-microamp",
+ &sreg->eco_uA);
+ if (ret) {
+ sreg->eco_uA = 0;
+ ret = 0;
+ }
+
+dt_parse_common_end:
+ return ret;
+}
+
+static int hi6421_dt_parse_ldo(struct hi6421_regulator *sreg,
+ struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct regulator_desc *rdesc = &sreg->rdesc;
+ unsigned int *v_table;
+ int ret = 0;
+
+ /* parse .n_voltages, and .volt_table */
+ ret = of_property_read_u32(np, "hisilicon,hi6421-n-voltages",
+ &rdesc->n_voltages);
+ if (ret) {
+ dev_err(dev, "no hisilicon,hi6421-n-voltages property set\n");
+ goto dt_parse_ldo_end;
+ }
+
+ /* alloc space for .volt_table */
+ v_table = devm_kzalloc(dev, sizeof(unsigned int) * rdesc->n_voltages,
+ GFP_KERNEL);
+ if (unlikely(!v_table)) {
+ ret = -ENOMEM;
+ dev_err(dev, "no memory for .volt_table\n");
+ goto dt_parse_ldo_end;
+ }
+
+ ret = of_property_read_u32_array(np, "hisilicon,hi6421-vset-table",
+ v_table, rdesc->n_voltages);
+ if (ret) {
+ dev_err(dev, "no hisilicon,hi6421-vset-table property set\n");
+ goto dt_parse_ldo_end;
+ }
+ rdesc->volt_table = v_table;
+
+ /* parse hi6421 regulator's dt common part */
+ ret = hi6421_dt_parse_common(sreg, pdev);
+ if (ret) {
+ dev_err(dev, "failure in hi6421_dt_parse_common\n");
+ goto dt_parse_ldo_end;
+ }
+
+dt_parse_ldo_end:
+ return ret;
+}
+
+static int hi6421_dt_parse_buck012(struct hi6421_regulator *sreg,
+ struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct regulator_desc *rdesc = &sreg->rdesc;
+ int ret = 0;
+
+ /* parse .n_voltages, and .uV_step */
+ ret = of_property_read_u32(np, "hisilicon,hi6421-n-voltages",
+ &rdesc->n_voltages);
+ if (ret) {
+ dev_err(dev, "no hisilicon,hi6421-n-voltages property set\n");
+ goto dt_parse_buck012_end;
+ }
+ ret = of_property_read_u32(np, "hisilicon,hi6421-uv-step",
+ &rdesc->uV_step);
+ if (ret) {
+ dev_err(dev, "no hisilicon,hi6421-uv-step property set\n");
+ goto dt_parse_buck012_end;
+ }
+
+ /* parse hi6421 regulator's dt common part */
+ ret = hi6421_dt_parse_common(sreg, pdev);
+ if (ret) {
+ dev_err(dev, "failure in hi6421_dt_parse_common\n");
+ goto dt_parse_buck012_end;
+ }
+
+dt_parse_buck012_end:
+ return ret;
+}
+
+static struct regulator_ops hi6421_ldo_rops = {
+ .is_enabled = hi6421_regulator_is_enabled,
+ .enable = hi6421_regulator_enable,
+ .disable = hi6421_regulator_disable,
+ .list_voltage = regulator_list_voltage_table,
+ .get_voltage = hi6421_regulator_get_voltage,
+ .set_voltage = hi6421_regulator_ldo_set_voltage,
+ .get_mode = hi6421_regulator_get_mode,
+ .set_mode = hi6421_regulator_set_mode,
+ .get_optimum_mode = hi6421_regulator_get_optimum_mode,
+};
+
+static struct regulator_ops hi6421_buck012_rops = {
+ .is_enabled = hi6421_regulator_is_enabled,
+ .enable = hi6421_regulator_enable,
+ .disable = hi6421_regulator_disable,
+ .list_voltage = regulator_list_voltage_linear,
+ .get_voltage = hi6421_regulator_get_voltage,
+ .set_voltage = hi6421_regulator_buck012_set_voltage,
+ .get_mode = hi6421_regulator_get_mode,
+ .set_mode = hi6421_regulator_set_mode,
+ .get_optimum_mode = hi6421_regulator_get_optimum_mode,
+};
+
+static struct regulator_ops hi6421_buck345_rops = {
+ .is_enabled = hi6421_regulator_is_enabled,
+ .enable = hi6421_regulator_enable,
+ .disable = hi6421_regulator_disable,
+ .list_voltage = regulator_list_voltage_table,
+ .get_voltage = hi6421_regulator_get_voltage,
+ .set_voltage = hi6421_regulator_ldo_set_voltage,
+ .get_mode = hi6421_regulator_get_mode,
+ .set_mode = hi6421_regulator_set_mode,
+ .get_optimum_mode = hi6421_regulator_get_optimum_mode,
+};
+
+static const struct hi6421_regulator hi6421_regulator_ldo = {
+ .rdesc = {
+ .ops = &hi6421_ldo_rops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ .dt_parse = hi6421_dt_parse_ldo,
+};
+
+static const struct hi6421_regulator hi6421_regulator_buck012 = {
+ .rdesc = {
+ .ops = &hi6421_buck012_rops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ .dt_parse = hi6421_dt_parse_buck012,
+};
+
+static const struct hi6421_regulator hi6421_regulator_buck345 = {
+ .rdesc = {
+ .ops = &hi6421_buck345_rops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ .dt_parse = hi6421_dt_parse_ldo,
+};
+
+static struct of_device_id of_hi6421_regulator_match_tbl[] = {
+ {
+ .compatible = "hisilicon,hi6421-ldo",
+ .data = &hi6421_regulator_ldo,
+ },
+ {
+ .compatible = "hisilicon,hi6421-buck012",
+ .data = &hi6421_regulator_buck012,
+ },
+ {
+ .compatible = "hisilicon,hi6421-buck345",
+ .data = &hi6421_regulator_buck345,
+ },
+ { /* end */ }
+};
+
+static int hi6421_regulator_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct regulator_desc *rdesc;
+ struct regulator_dev *rdev;
+ struct hi6421_regulator *sreg = NULL;
+ struct regulator_init_data *initdata;
+ struct regulation_constraints *c;
+ struct regulator_config config = { };
+ const struct of_device_id *match;
+ const struct hi6421_regulator *template = NULL;
+ int ret = 0;
+
+ /* to check which type of regulator this is */
+ match = of_match_device(of_hi6421_regulator_match_tbl, &pdev->dev);
+ if (match)
+ template = match->data;
+ else
+ return -EINVAL;
+
+ initdata = of_get_regulator_init_data(dev, np);
+
+ /* hi6421 regulator supports two modes */
+ c = &initdata->constraints;
+ c->valid_modes_mask = REGULATOR_MODE_NORMAL | REGULATOR_MODE_IDLE;
+ c->valid_ops_mask |= (REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_DRMS);
+ c->input_uV = c->min_uV;
+
+ sreg = devm_kzalloc(dev, sizeof(*sreg), GFP_KERNEL);
+ if (sreg == NULL)
+ return -ENOMEM;
+ memcpy(sreg, template, sizeof(*sreg));
+
+ sreg->name = initdata->constraints.name;
+ rdesc = &sreg->rdesc;
+ rdesc->name = sreg->name;
+ rdesc->min_uV = initdata->constraints.min_uV;
+ if (of_get_property(np, "ldo-supply", NULL)) {
+ rdesc->supply_name = "ldo";
+ }
+
+ /* to parse device tree data for regulator specific */
+ ret = sreg->dt_parse(sreg, pdev);
+ if (ret) {
+ dev_err(dev, "device tree parameter parse error!\n");
+ goto hi6421_probe_end;
+ }
+
+ config.dev = &pdev->dev;
+ config.init_data = initdata;
+ config.driver_data = sreg;
+ config.of_node = pdev->dev.of_node;
+
+ /* register regulator */
+ rdev = regulator_register(rdesc, &config);
+ if (IS_ERR(rdev)) {
+ dev_err(dev, "failed to register %s\n",
+ rdesc->name);
+ ret = PTR_ERR(rdev);
+ goto hi6421_probe_end;
+ }
+
+ platform_set_drvdata(pdev, rdev);
+
+hi6421_probe_end:
+ return ret;
+}
+
+static int hi6421_regulator_remove(struct platform_device *pdev)
+{
+ struct regulator_dev *rdev = platform_get_drvdata(pdev);
+ struct hi6421_regulator *sreg = rdev_get_drvdata(rdev);
+
+ regulator_unregister(rdev);
+
+ return 0;
+}
+
+static struct platform_driver hi6421_regulator_driver = {
+ .driver = {
+ .name = "hi6421_regulator",
+ .owner = THIS_MODULE,
+ .of_match_table = of_hi6421_regulator_match_tbl,
+ },
+ .probe = hi6421_regulator_probe,
+ .remove = hi6421_regulator_remove,
+};
+module_platform_driver(hi6421_regulator_driver);
+
+MODULE_AUTHOR("Guodong Xu <guodong.xu@linaro.org>");
+MODULE_DESCRIPTION("Hi6421 regulator driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index b9838130a7b0..d2a8577bdfc5 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -208,6 +208,17 @@ config RTC_DRV_LP8788
help
Say Y to enable support for the LP8788 RTC/ALARM driver.
+config RTC_DRV_HI6421
+ tristate "Hisilicon Hi6421 RTC"
+ depends on MFD_HI6421_PMIC
+ help
+ If you say yes here you get support for Hisilicon Hi6421 PMIC
+ RTC functions. If an interrupt is associated with the device,
+ the alarm functionality is supported.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-hi6421.
+
config RTC_DRV_MAX6900
tristate "Maxim MAX6900"
help
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index c33f86f1a69b..b71f81793e04 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -53,6 +53,7 @@ obj-$(CONFIG_RTC_DRV_EM3027) += rtc-em3027.o
obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o
obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.o
obj-$(CONFIG_RTC_DRV_GENERIC) += rtc-generic.o
+obj-$(CONFIG_RTC_DRV_HI6421) += rtc-hi6421.o
obj-$(CONFIG_RTC_DRV_HID_SENSOR_TIME) += rtc-hid-sensor-time.o
obj-$(CONFIG_RTC_DRV_IMXDI) += rtc-imxdi.o
obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o
diff --git a/drivers/rtc/rtc-hi6421.c b/drivers/rtc/rtc-hi6421.c
new file mode 100644
index 000000000000..50ec3911861b
--- /dev/null
+++ b/drivers/rtc/rtc-hi6421.c
@@ -0,0 +1,259 @@
+/*
+ * Hisilicon Hi6421 RTC driver
+ *
+ * Copyright (C) 2013 Hisilicon Ltd.
+ * Copyright (C) 2013 Linaro Ltd.
+ *
+ * Author: Haojian Zhuang <haojian.zhuang@linaro.org>
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of_device.h>
+#include <linux/rtc.h>
+#include <linux/mfd/hi6421-pmic.h>
+
+#define REG_IRQ1 0x01
+#define REG_IRQM1 0x04
+#define REG_RTCDR0 0x58
+#define REG_RTCDR1 0x59
+#define REG_RTCDR2 0x5a
+#define REG_RTCDR3 0x5b
+#define REG_RTCMR0 0x5c
+#define REG_RTCMR1 0x5d
+#define REG_RTCMR2 0x5e
+#define REG_RTCMR3 0x5f
+#define REG_RTCLR0 0x60
+#define REG_RTCLR1 0x61
+#define REG_RTCLR2 0x62
+#define REG_RTCLR3 0x63
+#define REG_RTCCTRL 0x64
+#define REG_SOFT_RST 0x86
+
+#define ALARM_ON (1 << HI6421_IRQ_ALARM)
+
+struct hi6421_rtc_info {
+ struct rtc_device *rtc;
+ struct hi6421_pmic *pmic;
+ int irq;
+};
+
+static irqreturn_t hi6421_rtc_handler(int irq, void *data)
+{
+ struct hi6421_rtc_info *info = (struct hi6421_rtc_info *)data;
+
+ /* clear alarm status */
+ hi6421_pmic_rmw(info->pmic, REG_IRQ1, ALARM_ON, ALARM_ON);
+ rtc_update_irq(info->rtc, 1, RTC_AF);
+ return IRQ_HANDLED;
+}
+
+/* read 4 8-bit registers & covert it into a 32-bit data */
+static unsigned int hi6421_read_bulk(struct hi6421_pmic *pmic,
+ unsigned int addr)
+{
+ unsigned int data, sum = 0;
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ data = hi6421_pmic_read(pmic, addr + i);
+ sum |= (data & 0xff) << (i * 8);
+ }
+ return sum;
+}
+
+/* write a 32-bit data into 4 8-bit registers */
+static void hi6421_write_bulk(struct hi6421_pmic *pmic, unsigned int addr,
+ unsigned int data)
+{
+ unsigned int value;
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ value = (data >> (i * 8)) & 0xff;
+ hi6421_pmic_write(pmic, addr + i, value);
+ }
+}
+
+static int hi6421_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct hi6421_rtc_info *info = dev_get_drvdata(dev);
+ unsigned long ticks;
+
+ ticks = hi6421_read_bulk(info->pmic, REG_RTCDR0);
+ rtc_time_to_tm(ticks, tm);
+ return 0;
+}
+
+static int hi6421_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct hi6421_rtc_info *info = dev_get_drvdata(dev);
+ unsigned long ticks;
+
+ if ((tm->tm_year < 70) || (tm->tm_year > 138)) {
+ dev_dbg(dev, "Set time %d out of range. "
+ "Please set time between 1970 to 2038.\n",
+ 1900 + tm->tm_year);
+ return -EINVAL;
+ }
+ rtc_tm_to_time(tm, &ticks);
+ hi6421_write_bulk(info->pmic, REG_RTCLR0, ticks);
+ return 0;
+}
+
+static int hi6421_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct hi6421_rtc_info *info = dev_get_drvdata(dev);
+ unsigned long ticks, data;
+
+ ticks = hi6421_read_bulk(info->pmic, REG_RTCMR0);
+ rtc_time_to_tm(ticks, &alrm->time);
+
+ data = hi6421_pmic_read(info->pmic, REG_IRQ1);
+ alrm->pending = (data & ALARM_ON) ? 1 : 0;
+
+ data = hi6421_pmic_read(info->pmic, REG_IRQM1);
+ alrm->enabled = (data & ALARM_ON) ? 0 : 1;
+ return 0;
+}
+
+/*
+ * Calculate the next alarm time given the requested alarm time mask
+ * and the current time.
+ */
+static void rtc_next_alarm_time(struct rtc_time *next, struct rtc_time *now,
+ struct rtc_time *alrm)
+{
+ unsigned long next_time;
+ unsigned long now_time;
+
+ next->tm_year = now->tm_year;
+ next->tm_mon = now->tm_mon;
+ next->tm_mday = now->tm_mday;
+ next->tm_hour = alrm->tm_hour;
+ next->tm_min = alrm->tm_min;
+ next->tm_sec = alrm->tm_sec;
+
+ rtc_tm_to_time(now, &now_time);
+ rtc_tm_to_time(next, &next_time);
+
+ if (next_time < now_time) {
+ /* Advance one day */
+ next_time += 60 * 60 * 24;
+ rtc_time_to_tm(next_time, next);
+ }
+}
+
+static int hi6421_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct hi6421_rtc_info *info = dev_get_drvdata(dev);
+ struct rtc_time now_tm, alarm_tm;
+ unsigned long ticks;
+
+ /* load 32-bit read-only counter */
+ ticks = hi6421_read_bulk(info->pmic, REG_RTCDR0);
+ rtc_time_to_tm(ticks, &now_tm);
+ dev_dbg(dev, "%s, now time : %lu\n", __func__, ticks);
+ rtc_next_alarm_time(&alarm_tm, &now_tm, &alrm->time);
+
+ /* get new ticks for alarm in 24 hours */
+ rtc_tm_to_time(&alarm_tm, &ticks);
+ dev_dbg(dev, "%s, alarm time: %lu\n", __func__, ticks);
+ if (alrm->enabled)
+ hi6421_write_bulk(info->pmic, REG_RTCMR0, ticks);
+ return 0;
+}
+
+static int hi6421_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+ struct hi6421_rtc_info *info = dev_get_drvdata(dev);
+ unsigned int data = 0;
+
+ if (!enabled)
+ data = ALARM_ON;
+ hi6421_pmic_rmw(info->pmic, REG_IRQM1, ALARM_ON, data);
+ return 0;
+}
+
+static const struct rtc_class_ops hi6421_rtc_ops = {
+ .read_time = hi6421_rtc_read_time,
+ .set_time = hi6421_rtc_set_time,
+ .read_alarm = hi6421_rtc_read_alarm,
+ .set_alarm = hi6421_rtc_set_alarm,
+ .alarm_irq_enable = hi6421_rtc_alarm_irq_enable,
+};
+
+static int hi6421_rtc_probe(struct platform_device *pdev)
+{
+ struct hi6421_rtc_info *info;
+ int ret;
+
+ info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+ if (!info) {
+ dev_err(&pdev->dev, "failed to allocate memory\n");
+ return -ENOMEM;
+ }
+ info->irq = platform_get_irq(pdev, 0);
+ if (info->irq < 0)
+ return -ENOENT;
+
+ info->pmic = dev_get_drvdata(pdev->dev.parent);
+ platform_set_drvdata(pdev, info);
+
+ /* enable RTC device */
+ hi6421_pmic_write(info->pmic, REG_RTCCTRL, 1);
+
+ info->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
+ &hi6421_rtc_ops, THIS_MODULE);
+ if (IS_ERR(info->rtc))
+ return PTR_ERR(info->rtc);
+
+ ret = devm_request_irq(&pdev->dev, info->irq, hi6421_rtc_handler,
+ IRQF_DISABLED, "alarm", info);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int hi6421_rtc_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static struct of_device_id hi6421_rtc_of_match[] = {
+ { .compatible = "hisilicon,hi6421-rtc" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, hi6421_rtc_of_match);
+
+static struct platform_driver hi6421_rtc_driver = {
+ .driver = {
+ .name = "hi6421-rtc",
+ .of_match_table = of_match_ptr(hi6421_rtc_of_match),
+ },
+ .probe = hi6421_rtc_probe,
+ .remove = hi6421_rtc_remove,
+};
+module_platform_driver(hi6421_rtc_driver);
+
+MODULE_LICENSE("GPLv2");
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@linaro.org");
+MODULE_ALIAS("platform:hi6421-rtc");
diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c
index 0f0609b1aa2c..8851e6b807c6 100644
--- a/drivers/rtc/rtc-pl031.c
+++ b/drivers/rtc/rtc-pl031.c
@@ -371,6 +371,7 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id)
}
}
+ device_init_wakeup(&adev->dev, 1);
ldata->rtc = rtc_device_register("pl031", &adev->dev, ops,
THIS_MODULE);
if (IS_ERR(ldata->rtc)) {
@@ -402,6 +403,32 @@ err_req:
return ret;
}
+#ifdef CONFIG_PM
+static int pl031_suspend(struct device *dev)
+{
+ struct amba_device *adev = to_amba_device(dev);
+
+ if (adev->irq[0] >= 0 && device_may_wakeup(&adev->dev))
+ enable_irq_wake(adev->irq[0]);
+ return 0;
+}
+
+static int pl031_resume(struct device *dev)
+{
+ struct amba_device *adev = to_amba_device(dev);
+
+ if (adev->irq[0] >= 0 && device_may_wakeup(&adev->dev))
+ disable_irq_wake(adev->irq[0]);
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(pl031_pm, pl031_suspend, pl031_resume);
+
+#define PL031_PM (&pl031_pm)
+#else
+#define PL031_PM NULL
+#endif
+
/* Operations for the original ARM version */
static struct pl031_vendor_data arm_pl031 = {
.ops = {
@@ -471,6 +498,7 @@ MODULE_DEVICE_TABLE(amba, pl031_ids);
static struct amba_driver pl031_driver = {
.drv = {
.name = "rtc-pl031",
+ .pm = PL031_PM,
},
.id_table = pl031_ids,
.probe = pl031_probe,
diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c
index 3511b0840362..2685008e17b1 100644
--- a/drivers/staging/android/ashmem.c
+++ b/drivers/staging/android/ashmem.c
@@ -231,8 +231,20 @@ static ssize_t ashmem_read(struct file *file, char __user *buf,
goto out_unlock;
}
+ if (!asma->file->f_op) {
+ pr_info("asma->file->f_op is NULL\n");
+ ret = -EBADF;
+ goto out_unlock;
+ }
+
+ if (!asma->file->f_op->read) {
+ pr_info("asma->file->f_op->read is NULL\n");
+ ret = -EBADF;
+ goto out_unlock;
+ }
mutex_unlock(&ashmem_mutex);
+
/*
* asma and asma->file are used outside the lock here. We assume
* once asma->file is set it will never be changed, and will not
@@ -268,6 +280,18 @@ static loff_t ashmem_llseek(struct file *file, loff_t offset, int origin)
goto out;
}
+ if (!asma->file->f_op) {
+ pr_info("asma->file->f_op is NULL\n");
+ ret = -EBADF;
+ goto out;
+ }
+
+ if (!asma->file->f_op->llseek) {
+ pr_info("asma->file->f_op->llseek is NULL\n");
+ ret = -EBADF;
+ goto out;
+ }
+
ret = asma->file->f_op->llseek(asma->file, offset, origin);
if (ret < 0)
goto out;
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index a3279c7def71..6eba25e5e350 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -2494,6 +2494,7 @@ config FB_SIMPLE
source "drivers/video/omap/Kconfig"
source "drivers/video/omap2/Kconfig"
source "drivers/video/exynos/Kconfig"
+source "drivers/video/hisilicon/Kconfig"
source "drivers/video/mmp/Kconfig"
source "drivers/video/backlight/Kconfig"
source "drivers/video/adf/Kconfig"
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 3adbd32eb091..8b6269857b99 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -47,6 +47,7 @@ obj-$(CONFIG_FB_RIVA) += riva/
obj-$(CONFIG_FB_NVIDIA) += nvidia/
obj-$(CONFIG_FB_ATY) += aty/ macmodes.o
obj-$(CONFIG_FB_ATY128) += aty/ macmodes.o
+obj-$(CONFIG_FB_HI3620) += hisilicon/
obj-$(CONFIG_FB_RADEON) += aty/
obj-$(CONFIG_FB_SIS) += sis/
obj-$(CONFIG_FB_VIA) += via/
diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c
index 6103fa6fb54f..f5c5f6644d17 100644
--- a/drivers/video/fbmon.c
+++ b/drivers/video/fbmon.c
@@ -1398,6 +1398,7 @@ int fb_videomode_from_videomode(const struct videomode *vm,
fbmode->sync = 0;
fbmode->vmode = 0;
+ fbmode->flag = 0;
if (vm->flags & DISPLAY_FLAGS_HSYNC_HIGH)
fbmode->sync |= FB_SYNC_HOR_HIGH_ACT;
if (vm->flags & DISPLAY_FLAGS_VSYNC_HIGH)
@@ -1406,7 +1407,14 @@ int fb_videomode_from_videomode(const struct videomode *vm,
fbmode->vmode |= FB_VMODE_INTERLACED;
if (vm->flags & DISPLAY_FLAGS_DOUBLESCAN)
fbmode->vmode |= FB_VMODE_DOUBLE;
- fbmode->flag = 0;
+ if (vm->flags & DISPLAY_FLAGS_DE_HIGH)
+ fbmode->flag |= FB_FLAG_DE_HIGH;
+ if (vm->flags & DISPLAY_FLAGS_DE_LOW)
+ fbmode->flag |= FB_FLAG_DE_LOW;
+ if (vm->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE)
+ fbmode->flag |= FB_FLAG_PIXDATA_POSEDGE;
+ if (vm->flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)
+ fbmode->flag |= FB_FLAG_PIXDATA_NEGEDGE;
htotal = vm->hactive + vm->hfront_porch + vm->hback_porch +
vm->hsync_len;
diff --git a/drivers/video/hisilicon/Kconfig b/drivers/video/hisilicon/Kconfig
new file mode 100644
index 000000000000..3f59b0be78e0
--- /dev/null
+++ b/drivers/video/hisilicon/Kconfig
@@ -0,0 +1,11 @@
+config FB_HI3620
+ tristate "Hisilicon Hi3620 Frame Buffer support"
+ depends on FB && ARCH_HS
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ select FB_MODE_HELPERS
+ select VIDEOMODE_HELPERS
+ help
+ This is the frame buffer device driver for the Hisilicon Hi3620 LCD
+ controller.
diff --git a/drivers/video/hisilicon/Makefile b/drivers/video/hisilicon/Makefile
new file mode 100644
index 000000000000..1f4b79befe51
--- /dev/null
+++ b/drivers/video/hisilicon/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_FB_HI3620) += hi3620_fb.o
+obj-y += hi3620_dsi.o
diff --git a/drivers/video/hisilicon/hi3620_dsi.c b/drivers/video/hisilicon/hi3620_dsi.c
new file mode 100644
index 000000000000..e7140d2accb2
--- /dev/null
+++ b/drivers/video/hisilicon/hi3620_dsi.c
@@ -0,0 +1,626 @@
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include <linux/platform_data/hi3620-dsi.h>
+
+#include "hi3620_fb.h"
+
+/* DSI PHY internal register */
+#define DSI_PHY_CP_CURRENT 0x11
+#define DSI_PHY_LPF_CTRL 0x12
+#define DSI_PHY_PLL_UNLOCK_FILTER 0x16
+#define DSI_PHY_N_PLL 0x17
+#define DSI_PHY_M_PLL 0x18
+#define DSI_PHY_FACTOR 0x19
+#define DSI_PHY_HS_FREQ_RANGE 0x44
+
+#define PHY_ADDR (1 << 16)
+
+#define DTYPE_GEN_WRITE_HEAD 0x03
+#define DTYPE_GEN_WRITE_PAYLOAD 0x29
+
+struct phy_timing {
+ int dsi2x; /* MHz */
+ int lp2hs;
+ int hs2lp;
+ int hsfreq;
+};
+
+static struct device *dsi_dev = NULL;
+
+static void reset(void __iomem *reg_base)
+{
+ writel_relaxed(0, reg_base + DSI_PWR_UP);
+}
+
+static void unreset(void __iomem *reg_base)
+{
+ writel_relaxed(1, reg_base + DSI_PWR_UP);
+}
+
+static void set_highspeed(void __iomem *reg_base)
+{
+ unsigned int data;
+
+ /* enable high speed clock for PHY */
+ data = readl_relaxed(reg_base + DSI_PHY_IF_CTRL);
+ data |= (1 << 0);
+ writel_relaxed(data, reg_base + DSI_PHY_IF_CTRL);
+}
+
+static void unset_highspeed(void __iomem *reg_base)
+{
+ unsigned int data;
+
+ /* disable high speed clock for PHY */
+ data = readl_relaxed(reg_base + DSI_PHY_IF_CTRL);
+ data &= ~(1 << 0);
+ writel_relaxed(data, reg_base + DSI_PHY_IF_CTRL);
+}
+
+/* bit definition of register DSI_VID_MODE_CFG */
+#define VIDEO_MODE_EN (1 << 0)
+
+/* bit definition of register DSI_CMD_MODE_CFG */
+#define CMD_MODE_EN (1 << 0)
+#define CMD_MODE_LP (0x1ffe)
+
+static int is_video_mode(void __iomem *base)
+{
+ unsigned int data;
+
+ data = readl_relaxed(base + DSI_VID_MODE_CFG);
+ if (data & VIDEO_MODE_EN)
+ return 1;
+ return 0;
+}
+
+static int is_cmd_mode(void __iomem *base)
+{
+ unsigned int data;
+
+ data = readl_relaxed(base + DSI_CMD_MODE_CFG);
+ if (data & CMD_MODE_EN)
+ return 1;
+ return 0;
+}
+
+/* Switch to CMD mode with LP transmission */
+static void set_cmd_mode(void __iomem *base)
+{
+ unsigned int data;
+
+ /* disable VIDEO mode */
+ data = readl_relaxed(base + DSI_VID_MODE_CFG);
+ data &= ~VIDEO_MODE_EN;
+ writel_relaxed(data, base + DSI_VID_MODE_CFG);
+ /* enable COMMAND mode with LP transmission */
+ data = readl_relaxed(base + DSI_CMD_MODE_CFG);
+ data |= CMD_MODE_LP | CMD_MODE_EN;
+ writel_relaxed(data, base + DSI_CMD_MODE_CFG);
+}
+
+static void init_video_mode(void __iomem *base, struct hi3620fb_info *info)
+{
+ struct fb_var_screeninfo *var = &info->fb->var;
+ unsigned int data;
+
+ data = readl_relaxed(base + DSI_VID_MODE_CFG);
+ data |= 0x1f8; /* enable Low Power control */
+ data &= ~(3 << 1); /* mask video transfer mode */
+ data |= (2 << 1); /* Burst with Sync Pulses */
+ data &= ~0x800; /* Disable frame end ACK */
+ writel_relaxed(data, base + DSI_VID_MODE_CFG);
+ data = readl_relaxed(base + DSI_VID_PKT_CFG);
+ data &= ~0x7ff; /* mask single video packet size */
+ data |= var->xres;
+ writel_relaxed(data, base + DSI_VID_PKT_CFG);
+ data = readl_relaxed(base + DSI_PCKHDL_CFG);
+ data |= (1 << 2); /* enable Bus Turn-Around */
+ writel_relaxed(data, base + DSI_PCKHDL_CFG);
+}
+
+/* Switch to VIDEO mode */
+static void set_video_mode(void __iomem *base)
+{
+ unsigned int data;
+
+ /* disable CMD mode */
+ data = readl_relaxed(base + DSI_CMD_MODE_CFG);
+ data |= CMD_MODE_LP;
+ data &= ~CMD_MODE_EN;
+ writel_relaxed(data, base + DSI_CMD_MODE_CFG);
+ /* enable VIDEO mode */
+ data = readl_relaxed(base + DSI_VID_MODE_CFG);
+ data |= VIDEO_MODE_EN;
+ writel_relaxed(data, base + DSI_VID_MODE_CFG);
+}
+
+static void set_dpi_timing(struct hi3620fb_info *info)
+{
+ void __iomem *base = info->reg_base;
+ struct fb_videomode *fb_vm = info->fb->mode;
+ unsigned int dsi_rate, lane_rate, pixclock, data, timing;
+ unsigned long long int tmp;
+
+ dsi_rate = clk_get_rate(info->clk_dsi); /* dsi1x, not dsi2x */
+ lane_rate = dsi_rate / 4; /* dsi2x / 8 */
+
+ pixclock = PICOS2KHZ(fb_vm->pixclock) * 1000;
+ tmp = (unsigned long long int)(fb_vm->hsync_len) * lane_rate;
+ do_div(tmp, pixclock);
+ data = (unsigned int)tmp;
+ timing = data & 0x1ff;
+ tmp = (unsigned long long int)(fb_vm->left_margin) * lane_rate;
+ do_div(tmp, pixclock);
+ data = (unsigned int)tmp;
+ timing |= (data & 0x1ff) << 9;
+ tmp = (unsigned long long int)(fb_vm->left_margin + fb_vm->xres +
+ fb_vm->right_margin + fb_vm->hsync_len);
+ tmp *= lane_rate;
+ do_div(tmp, pixclock);
+ data = (unsigned int)tmp;
+ timing |= data << 18;
+ writel_relaxed(timing, info->reg_base + DSI_TMR_LINE_CFG);
+
+ /* setup frame timing */
+ timing = (fb_vm->vsync_len) & 0xf;
+ timing |= ((fb_vm->upper_margin) & 0x3f) << 4;
+ timing |= ((fb_vm->lower_margin) & 0x3f) << 10;
+ timing |= ((fb_vm->yres) & 0x7ff) << 16;
+ writel_relaxed(timing, info->reg_base + DSI_VTIMING_CFG);
+}
+
+#define PHY_TX_OUT_LP_DATA (1 << 4)
+#define PHY_TX_IN_LP_DATA (1 << 3)
+#define PHY_TX_OUT_LP_CLK (1 << 2)
+#define PHY_TX_IN_LP_CLK (1 << 1)
+#define PHY_TX_REQ_HS_CLK (1 << 0)
+#define PHY_TX_MASK 0x1f
+
+static int is_phy_hs(void __iomem *base)
+{
+ unsigned int data, expected;
+
+ data = readl_relaxed(base + DSI_PHY_IF_CTRL);
+ expected = PHY_TX_OUT_LP_DATA | PHY_TX_OUT_LP_CLK | PHY_TX_REQ_HS_CLK;
+ if ((data & PHY_TX_MASK) == expected)
+ return 1;
+ return 0;
+}
+
+static int is_phy_lp(void __iomem *base)
+{
+ unsigned int data, expected;
+
+ data = readl_relaxed(base + DSI_PHY_IF_CTRL);
+ expected = PHY_TX_IN_LP_DATA | PHY_TX_IN_LP_CLK;
+ if ((data & PHY_TX_MASK) == expected)
+ return 1;
+ return 0;
+}
+
+static int set_phy_hs(void __iomem *base)
+{
+ unsigned int data;
+
+ data = readl_relaxed(base + DSI_PHY_IF_CTRL);
+ data &= ~PHY_TX_MASK;
+ data |= PHY_TX_OUT_LP_DATA | PHY_TX_OUT_LP_CLK;
+ writel_relaxed(data, base + DSI_PHY_IF_CTRL);
+ data = readl_relaxed(base + DSI_PHY_IF_CTRL);
+ return 0;
+}
+
+static int set_phy_lp(void __iomem *base)
+{
+ unsigned int data;
+
+ data = readl_relaxed(base + DSI_PHY_IF_CTRL);
+ data &= ~PHY_TX_MASK;
+ data |= PHY_TX_OUT_LP_DATA | PHY_TX_OUT_LP_CLK;
+ writel_relaxed(data, base + DSI_PHY_IF_CTRL);
+ data = readl_relaxed(base + DSI_PHY_IF_CTRL);
+ return 0;
+}
+
+static void enable_phy(void __iomem *base)
+{
+ unsigned int status, mask;
+
+ writel_relaxed(0x7, base + DSI_PHY_RSTZ);
+ mask = DSI_PHY_STOP_STATE0_LANE | DSI_PHY_LOCK;
+ do {
+ cpu_relax();
+ status = readl_relaxed(base + DSI_PHY_STATUS);
+ } while ((status & mask) != mask);
+}
+
+static void disable_phy(void __iomem *reg_base)
+{
+ writel_relaxed(0, reg_base + DSI_PHY_RSTZ);
+}
+
+void hi3620_mipi_dsi_set_video_packet_size(void __iomem *reg_base,
+ int null_pkt_size, int num_vid_pkt,
+ int vid_pkt_size)
+{
+ unsigned int data;
+ data = (null_pkt_size & 0x3ff) << 21; /* byte size */
+ /* number of video packets for Each Multiple Packets */
+ data |= (num_vid_pkt & 0x3ff) << 11;
+ /* pixels of each video packet */
+ data |= vid_pkt_size & 0x7ff;
+ writel_relaxed(data, reg_base + DSI_VID_PKT_CFG);
+}
+
+static void hi3620_mipi_setup_dpi(struct hi3620fb_info *info)
+{
+ unsigned int data;
+
+ /* set lane numbers */
+ /*
+ data = readl_relaxed(info->reg_base + DSI_PHY_IF_CFG) & ~0x3;
+ data |= (info->lane_cnt - 1) & 0x3;
+ writel_relaxed(data, info->reg_base + DSI_PHY_IF_CFG);
+ */
+ data = 0;
+ //data = readl_relaxed(info->reg_base + DSI_DPI_CFG);
+ /* set virtual channel ID as 0 */
+ data &= ~(3 << 0);
+ /* set color mode */
+ data &= ~(7 << 2);
+ data |= info->color_mode << 2;
+ /* always set color mode & shutdown high active */
+ writel_relaxed(data, info->reg_base + DSI_DPI_CFG);
+}
+
+#define MAX_TX_ESC_CLK (10 * 1000 * 1000)
+
+static void setup_phy(struct hi3620fb_info *info)
+{
+ struct clk *parent;
+ unsigned char hs2lp = 0, lp2hs = 0, hsfreq = 0;
+ unsigned int data;
+ void __iomem *base = info->reg_base;
+ int rate, rate_mhz, dsi_rate, lane_rate, i;
+ struct phy_timing timing[] = {
+ {90, 24, 14, 0}, {100, 25, 14, 0x20},
+ {110, 25, 14, 0x40}, {125, 25, 14, 0x02},
+ {140, 25, 14, 0x22}, {150, 25, 14, 0x42},
+ {160, 25, 14, 0x04}, {180, 28, 16, 0x24},
+ {200, 32, 16, 0x44}, {210, 31, 16, 0x06},
+ {240, 35, 17, 0x26}, {250, 37, 18, 0x46},
+ {270, 37, 18, 0x08}, {300, 39, 19, 0x28},
+ {330, 44, 20, 0x08}, {360, 47, 21, 0x2a},
+ {400, 48, 21, 0x4a}, {450, 54, 23, 0x0c},
+ {500, 58, 25, 0x2c}, {550, 62, 26, 0x0e},
+ {600, 67, 28, 0x2e}, {650, 72, 30, 0x10},
+ {700, 76, 31, 0x30}, {750, 81, 32, 0x12},
+ {800, 86, 34, 0x32}, {850, 89, 35, 0x14},
+ {900, 95, 37, 0x34}, {950, 99, 38, 0x54},
+ {1000, 104, 40, 0x74}, };
+ parent = clk_get_parent(info->clk_dsi);
+ rate = clk_get_rate(parent);
+ rate_mhz = rate / 1000000;
+ for (i = 0; i < ARRAY_SIZE(timing); i++) {
+ if (rate_mhz <= timing[i].dsi2x) {
+ hs2lp = timing[i].hs2lp;
+ lp2hs = timing[i].lp2hs;
+ hsfreq = timing[i].hsfreq;
+ break;
+ }
+ }
+
+ /* setup PHY timing */
+ data = 4095; /* bta time */
+ data |= (lp2hs & 0xff) << 16;
+ data |= (hs2lp & 0xff) << 24;
+ writel_relaxed(data, base + DSI_PHY_TMR_CFG);
+ /* set hsfreqrange */
+ hi3620_dsi_phy_write(base, 0x44, hsfreq);
+ writel_relaxed(0x7, base + DSI_PHY_RSTZ);
+
+#if 0
+ /* set tx esc clk division */
+ dsi_rate = clk_get_rate(info->clk_dsi);
+ lane_rate = dsi_rate / 4;
+ data = (lane_rate + (MAX_TX_ESC_CLK / 2) - 1) / MAX_TX_ESC_CLK;
+ writel_relaxed(data, base + DSI_CLKMGR_CFG);
+#endif
+}
+
+void hi3620_mipi_dsi_set_lane(void __iomem *reg_base, int id, int count)
+{
+ unsigned int data, cnt;
+
+ cnt = count - 1;
+ if (cnt < 0 || id > cnt)
+ return;
+ data = readl_relaxed(reg_base + DSI_PHY_IF_CFG) & ~0x3;
+ data |= cnt & 0x3;
+ writel_relaxed(data, reg_base + DSI_PHY_IF_CFG);
+ data = readl_relaxed(reg_base + DSI_DPI_CFG) & ~0x3;
+ data |= id & 0x3;
+ writel_relaxed(data, reg_base + DSI_DPI_CFG);
+}
+
+/*
+ * PHY_TST_CTRL0 & PHY_TST_CTRL1 registers are the interfaces of accessing
+ * PHY internal registers.
+ * PHY_TST_CTRL0 is used to produce clock, as I2C SCLK.
+ * PHY_TST_CTRL1 is used to store address or data, as I2C SDA.
+ */
+static void set_phy_testclk(void __iomem *reg_base, int level)
+{
+ unsigned int data;
+
+ if (level)
+ data = 0x2;
+ else
+ data = 0;
+ writel_relaxed(data, reg_base + DSI_PHY_TST_CTRL0);
+}
+
+/* write 8-bit data into 8-bit phy register */
+int hi3620_dsi_phy_write(void __iomem *reg_base, unsigned char addr,
+ unsigned char data)
+{
+ unsigned int value;
+
+ set_phy_testclk(reg_base, 0);
+ value = (unsigned int)addr | PHY_ADDR;
+ writel_relaxed(value, reg_base + DSI_PHY_TST_CTRL1);
+ set_phy_testclk(reg_base, 1);
+
+ set_phy_testclk(reg_base, 0);
+ value = (unsigned int)data;
+ writel_relaxed(value, reg_base + DSI_PHY_TST_CTRL1);
+ set_phy_testclk(reg_base, 1);
+ set_phy_testclk(reg_base, 0);
+ return 0;
+}
+EXPORT_SYMBOL(hi3620_dsi_phy_write);
+
+/* read 8-bit data from 8-bit phy register */
+unsigned char hi3620_dsi_phy_read(void __iomem *reg_base, unsigned char addr)
+{
+ unsigned int value;
+
+ set_phy_testclk(reg_base, 0);
+ value = (unsigned int)addr | PHY_ADDR;
+ writel_relaxed(value, reg_base + DSI_PHY_TST_CTRL1);
+ set_phy_testclk(reg_base, 1);
+ set_phy_testclk(reg_base, 0);
+ value = readl_relaxed(reg_base + DSI_PHY_TST_CTRL1);
+ return (unsigned char)(value >> 8);
+}
+
+static bool is_wfifo_full(void __iomem *base)
+{
+ unsigned int status;
+
+ status = readl_relaxed(base + DSI_CMD_PKT_STATUS);
+ if (status & GEN_PLD_W_FULL)
+ return true;
+ return false;
+}
+
+static int recv_generic_pkt(void __iomem *base, u8 *val, int len)
+{
+ int i, cnt;
+ unsigned int status, data;
+
+ cnt = (len + 3) / 4;
+ for (i = 0; i < cnt; i++) {
+ do {
+ cpu_relax();
+ status = readl_relaxed(base + DSI_CMD_PKT_STATUS);
+ if (status & GEN_PLD_R_EMPTY) {
+ pr_err("#%s, %d, found empty read fifo\n",
+ __func__, __LINE__);
+ return -EINVAL;
+ }
+ } while (status & GEN_RD_CMD_BUSY);
+
+ data = readl_relaxed(base + DSI_GEN_PLD_DATA);
+ val[i * 4] = data & 0xff;
+ val[i * 4 + 1] = (data >> 8) & 0xff;
+ val[i * 4 + 2] = (data >> 16) & 0xff;
+ val[i * 4 + 3] = (data >> 24) & 0xff;
+ }
+ do {
+ cpu_relax();
+ status = readl_relaxed(base + DSI_CMD_PKT_STATUS);
+ /* read data until FIFO empty */
+ readl_relaxed(base + DSI_GEN_PLD_DATA);
+ } while (!(status & GEN_PLD_R_EMPTY));
+ return 0;
+}
+
+static void wait_phy_ready(void __iomem *base)
+{
+#if 0
+ unsigned int status;
+
+ do {
+ cpu_relax();
+ status = readl_relaxed(base + DSI_PHY_STATUS);
+ } while (!(status & DSI_PHY_STOP_STATE0_LANE));
+#else
+ /*
+ * In some board, it always loop as dead.
+ * So use delay as workaround.
+ */
+ msleep(5);
+#endif
+}
+
+int set_packet(struct device *dev, u8 *cmd, int nr_payload)
+{
+ struct hi3620fb_info *info = dev_get_drvdata(dev);
+ void __iomem *base = info->reg_base;
+ unsigned int header, type, data = 0;
+ int ret = 0, video_mode = 0, i = 0, j = 0;
+
+ mutex_lock(&info->dsi_mutex);
+ wait_phy_ready(base);
+ if (is_video_mode(base)) {
+ video_mode = 1;
+ set_cmd_mode(base);
+ }
+
+ /* set DT type */
+ type = cmd[0] & 0xff;
+ header = type;
+
+ switch (type) {
+ case DCS_SHORT_WR_PARAM0:
+ /* set DSI command */
+ header |= (cmd[1] & 0xff) << 8;
+ writel_relaxed(header, base + DSI_GEN_HDR);
+ break;
+ case DCS_SHORT_WR_PARAM1:
+ header |= (cmd[1] & 0xff) << 8;
+ header |= (cmd[2] & 0xff) << 16;
+ writel_relaxed(header, base + DSI_GEN_HDR);
+ break;
+ case GEN_LONG_WR:
+ for (i = 0; i < nr_payload;) {
+ data = 0;
+ for (j = 0; i < nr_payload && j < 4; i++, j++)
+ data |= cmd[i + 1] << (j * 8);
+ writel_relaxed(data, base + DSI_GEN_PLD_DATA);
+ if (is_wfifo_full(base))
+ pr_err("wfifo is full\n");
+ }
+ header |= nr_payload << 8;
+ writel_relaxed(header, base + DSI_GEN_HDR);
+ break;
+ case GEN_RD_PARAM1:
+ header |= (cmd[1] & 0xff) << 8;
+ writel_relaxed(header, base + DSI_GEN_HDR);
+ udelay(20); /* FIXME */
+ ret = recv_generic_pkt(base, &cmd[2], nr_payload);
+ break;
+ case DCS_RD_PARAM0:
+ header |= (cmd[1] & 0xff) << 8;
+ writel_relaxed(header, base + DSI_GEN_HDR);
+ udelay(20); /* FIXME */
+ ret = recv_generic_pkt(base, &cmd[2], 1);
+ break;
+ default:
+ pr_warn("###%s: not set packet type\n", __func__);
+ break;
+ }
+ wait_phy_ready(base);
+ /* restore video mode if necessary */
+ if (video_mode)
+ set_video_mode(base);
+ mutex_unlock(&info->dsi_mutex);
+ return ret;
+}
+
+static int write_packet(struct device *dev, enum DATA_TYPE type, u8 *cmd,
+ int len)
+{
+ struct hi3620fb_info *info = dev_get_drvdata(dev);
+ void __iomem *base = info->reg_base;
+ unsigned int header;
+ int ret, video_mode = 0;
+
+ if (is_video_mode(base)) {
+ video_mode = 1;
+ set_cmd_mode(base);
+ }
+
+ header = type & 0xff;
+ header |= (cmd[0] & 0xff) << 8;
+
+ switch (type) {
+ case DCS_SHORT_WR_PARAM0:
+ writel_relaxed(header, base + DSI_GEN_HDR);
+ break;
+ case DCS_SHORT_WR_PARAM1:
+ header |= (cmd[1] & 0xff) << 16;
+ writel_relaxed(header, base + DSI_GEN_HDR);
+ break;
+ default:
+ pr_err("#%s, %d, wrong type:%d\n", __func__, __LINE__, type);
+ break;
+ }
+ /* restore video mode if necessary */
+ if (video_mode)
+ set_video_mode(base);
+ return ret;
+}
+
+int dsi_set_packet(u8 *cmd, int nr_payload)
+{
+ if (dsi_dev)
+ return set_packet(dsi_dev, cmd, nr_payload);
+ else
+ return -EINVAL;
+}
+
+int hi3620_mipi_init(struct device *dev)
+{
+ struct hi3620fb_info *info = dev_get_drvdata(dev);
+
+ dsi_dev = dev;
+ mutex_init(&info->dsi_mutex);
+ return 0;
+}
+EXPORT_SYMBOL(hi3620_mipi_init);
+
+int hi3620_mipi_enable(struct device *dev)
+{
+ struct hi3620fb_info *info = dev_get_drvdata(dev);
+
+ unreset(info->reg_base);
+ init_video_mode(info->reg_base, info);
+
+ clk_set_rate(info->clk_dsi, info->dsi_rate); /* huawei logo is shifted to right & color may be changed??? */
+ set_dpi_timing(info);
+ clk_prepare_enable(info->clk_dsi);
+
+ setup_phy(info);
+ enable_phy(info->reg_base);
+
+ set_cmd_mode(info->reg_base);
+ unset_highspeed(info->reg_base);
+
+ /* set panel on */
+
+ if (!strncmp(info->mipi_mode_name, "video", 5))
+ set_video_mode(info->reg_base);
+ else if (!strncmp(info->mipi_mode_name, "command", 7))
+ set_cmd_mode(info->reg_base);
+ else
+ return -EINVAL;
+ set_highspeed(info->reg_base);
+ return 0;
+}
+EXPORT_SYMBOL(hi3620_mipi_enable);
+
+int hi3620_mipi_disable(struct device *dev)
+{
+ struct hi3620fb_info *info = dev_get_drvdata(dev);
+
+ /* set panel off */
+
+ set_cmd_mode(info->reg_base);
+ unset_highspeed(info->reg_base);
+ unreset(info->reg_base);
+ disable_phy(info->reg_base);
+ reset(info->reg_base);
+ clk_disable_unprepare(info->clk_dsi);
+ return 0;
+}
+EXPORT_SYMBOL(hi3620_mipi_disable);
diff --git a/drivers/video/hisilicon/hi3620_fb.c b/drivers/video/hisilicon/hi3620_fb.c
new file mode 100644
index 000000000000..634ad1375b1f
--- /dev/null
+++ b/drivers/video/hisilicon/hi3620_fb.c
@@ -0,0 +1,926 @@
+/*
+ * Framebuffer driver of Hisilicon Hi3620 SoC
+ *
+ * Copyright (c) 2013 Linaro Ltd.
+ * Copyright (c) 2013 Hisilicon Ltd.
+ *
+ * Author: Haojian Zhuang <haojian.zhuang@linaro.org>
+ *
+ * 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/module.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/fb.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/regulator/consumer.h>
+#include <linux/mfd/r63306.h>
+#include <video/of_display_timing.h>
+#include <video/display_timing.h>
+#include "hi3620_fb.h"
+
+static unsigned int hi3620fb_pseudo_palette[16] = {
+ 0, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL,
+ ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL,
+};
+
+static int match_fmt_555(struct fb_var_screeninfo *var)
+{
+ if (var->blue.offset == 0 && var->green.offset <= 5 &&
+ var->red.offset <= 10 && var->transp.offset <= 15 &&
+ var->blue.offset <= 5 && var->green.length <= 5 &&
+ var->red.length <= 5)
+ return 1;
+ return 0;
+}
+
+static int match_fmt_565(struct fb_var_screeninfo *var)
+{
+ if (var->blue.offset == 0 && var->green.offset <= 5 &&
+ var->red.offset <= 11 && var->transp.offset == 0 &&
+ var->blue.length <= 5 && var->green.length <= 6 &&
+ var->red.length <= 5 && var->transp.length == 0)
+ return 1;
+ return 0;
+}
+
+static int match_fmt_888(struct fb_var_screeninfo *var)
+{
+ if (var->blue.offset == 0 && var->green.offset <= 8 &&
+ var->red.offset <= 16 && var->transp.offset <= 24 &&
+ var->blue.length <= 8 && var->green.length <= 8 &&
+ var->red.length <= 8)
+ return 1;
+ return 0;
+}
+
+static int find_best_pix_fmt(struct fb_var_screeninfo *var)
+{
+ if (var->bits_per_pixel == 16) {
+ /* RGB565/RGBA5551/RGBX5551 */
+ if (match_fmt_555(var)) {
+ if (var->transp.length == 1)
+ return IMG_PIXEL_FORMAT_ARGB1555;
+ else if (var->transp.length == 0)
+ return IMG_PIXEL_FORMAT_RGB555;
+ } else if (match_fmt_565(var))
+ return IMG_PIXEL_FORMAT_RGB565;
+ } else if (var->bits_per_pixel == 32) {
+ if (match_fmt_888(var)) {
+ if (var->transp.length == 8)
+ return IMG_PIXEL_FORMAT_ARGB8888;
+ else if (var->transp.length == 0)
+ return IMG_PIXEL_FORMAT_RGB888;
+ }
+ }
+ return -EINVAL;
+}
+
+static void set_pix_fmt(struct hi3620fb_info *info, int pix_fmt)
+{
+ struct fb_info *fb = info->fb;
+ struct fb_var_screeninfo *var = &fb->var;
+
+ switch (pix_fmt) {
+ case IMG_PIXEL_FORMAT_RGB565:
+ var->blue.offset = 0;
+ var->blue.length = 5;
+ var->green.offset = 5;
+ var->green.length = 6;
+ var->red.offset = 11;
+ var->red.length = 5;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ var->bits_per_pixel = 16;
+ break;
+ case IMG_PIXEL_FORMAT_ARGB1555:
+ var->blue.offset = 0;
+ var->blue.length = 5;
+ var->green.offset = 5;
+ var->green.length = 5;
+ var->red.offset = 10;
+ var->red.length = 5;
+ var->transp.offset = 15;
+ var->transp.length = 1;
+ var->bits_per_pixel = 16;
+ break;
+ case IMG_PIXEL_FORMAT_RGB555:
+ var->blue.offset = 0;
+ var->blue.length = 5;
+ var->green.offset = 5;
+ var->green.length = 5;
+ var->red.offset = 10;
+ var->red.length = 5;
+ var->transp.offset = 15;
+ var->transp.length = 0;
+ var->bits_per_pixel = 16;
+ break;
+ case IMG_PIXEL_FORMAT_ARGB8888:
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->red.offset = 16;
+ var->red.length = 8;
+ var->transp.offset = 24;
+ var->transp.length = 8;
+ var->bits_per_pixel = 32;
+ break;
+ case IMG_PIXEL_FORMAT_RGB888:
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->red.offset = 16;
+ var->red.length = 8;
+ var->transp.offset = 24;
+ var->transp.length = 0;
+ var->bits_per_pixel = 32;
+ break;
+ default:
+ return;
+ }
+ info->pix_fmt = pix_fmt;
+}
+
+static int hi3620fb_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *fb)
+{
+ struct hi3620fb_info *info = fb->par;
+ int pix_fmt;
+
+ /*
+ * Determine which pixel format we're going to use.
+ */
+ pix_fmt = find_best_pix_fmt(var);
+ if (pix_fmt < 0)
+ return pix_fmt;
+ set_pix_fmt(info, pix_fmt);
+
+ /*
+ * Basic geometry sanity checks.
+ */
+ if (var->xoffset + var->xres > var->xres_virtual)
+ return -EINVAL;
+ if (var->yoffset + var->yres > var->yres_virtual)
+ return -EINVAL;
+ if (var->xres + var->right_margin +
+ var->hsync_len + var->left_margin > 2048)
+ return -EINVAL;
+ if (var->yres + var->lower_margin +
+ var->vsync_len + var->upper_margin > 2048)
+ return -EINVAL;
+
+ /*
+ * Check size of framebuffer.
+ */
+ if (var->xres_virtual * var->yres_virtual *
+ (var->bits_per_pixel >> 3) > fb->fix.smem_len)
+ return -EINVAL;
+ return 0;
+}
+
+/* It's used to make EDC configuration work. */
+static void update_edc(void __iomem *base)
+{
+ unsigned int data;
+
+ data = readl_relaxed(base + EDC_DISP_CTL);
+ writel_relaxed(data | EDC_CTRL_CFG_OK, base + EDC_DISP_CTL);
+ data &= ~EDC_CTRL_CFG_OK;
+ writel_relaxed(data, base + EDC_DISP_CTL);
+}
+
+static void disable_edc(void __iomem *base)
+{
+ unsigned int data;
+
+ data = readl_relaxed(base + LDI_CTRL);
+ data &= ~(LDI_CTRL_EN | LDI_CTRL_SHUTDOWN);
+ writel_relaxed(data, base + LDI_CTRL);
+ data = readl_relaxed(base + EDC_DISP_CTL);
+ data &= ~EDC_CTRL_EN;
+ data |= EDC_CTRL_CLK_EN;
+ writel_relaxed(data, base + EDC_DISP_CTL);
+ update_edc(base);
+ data = readl_relaxed(base + EDC_VIDEO_CHAN_CTRL);
+ data &= ~EDC_VIDEO_CHAN_CTRL_EN;
+ writel_relaxed(data, base + EDC_VIDEO_CHAN_CTRL);
+}
+
+static void enable_edc(void __iomem *base)
+{
+ unsigned int data;
+
+ data = readl_relaxed(base + EDC_VIDEO_CHAN_CTRL);
+ data |= EDC_VIDEO_CHAN_CTRL_EN;
+ writel_relaxed(data, base + EDC_VIDEO_CHAN_CTRL);
+
+ data = readl_relaxed(base + LDI_WORK_MODE);
+ data |= LDI_WORK_MODE_EN;
+ writel_relaxed(data, base + LDI_WORK_MODE);
+
+ data = readl_relaxed(base + LDI_CTRL);
+ data &= ~(LDI_CTRL_SHUTDOWN | LDI_CTRL_COLOR_MODE | LDI_CTRL_BGR);
+ data &= ~(LDI_CTRL_DISP_MODE);
+ data |= LDI_CTRL_EN | LDI_CTRL_DATA_GATE_EN;
+ writel_relaxed(data, base + LDI_CTRL);
+
+ data = readl_relaxed(base + EDC_DISP_CTL);
+ data |= EDC_CTRL_EN | EDC_CTRL_CLK_EN;
+ data &= ~(EDC_CTRL_CFG_OK_SEL | EDC_CTRL_FRAME_END_START);
+ /* unflow level */
+ data &= ~(0xfff << 11);
+ data |= (0xc00 << 11);
+ writel_relaxed(data, base + EDC_DISP_CTL);
+ update_edc(base);
+}
+
+static void set_panel_control(struct fb_info *fb)
+{
+ struct fb_videomode *fb_vm = fb->mode;
+ struct hi3620fb_info *info = fb->par;
+ void __iomem *base = info->reg_base;
+ u32 ldi, dpi;
+
+ ldi = readl_relaxed(base + LDI_PLR_CTRL) & ~LDI_POLARITY_MASK;
+ dpi = readl_relaxed(base + DSI_DPI_CFG) & ~DSI_DPI_POLARITY_MASK;
+ if (fb_vm->sync & FB_SYNC_HOR_HIGH_ACT) {
+ ldi &= ~LDI_HSYNC_POLARITY;
+ dpi &= ~DSI_DPI_HSYNC_POLARITY;
+ } else {
+ ldi |= LDI_HSYNC_POLARITY;
+ dpi |= DSI_DPI_HSYNC_POLARITY;
+ }
+ if (fb_vm->sync & FB_SYNC_VERT_HIGH_ACT) {
+ ldi &= ~LDI_VSYNC_POLARITY;
+ dpi &= ~DSI_DPI_VSYNC_POLARITY;
+ } else {
+ ldi |= LDI_VSYNC_POLARITY;
+ dpi |= DSI_DPI_VSYNC_POLARITY;
+ }
+ if (fb_vm->flag & FB_FLAG_DE_HIGH) {
+ ldi &= ~LDI_DATAEN_POLARITY;
+ dpi &= ~DSI_DPI_DATAEN_POLARITY;
+ }
+ if (fb_vm->flag & FB_FLAG_DE_LOW) {
+ ldi |= LDI_DATAEN_POLARITY;
+ dpi |= DSI_DPI_DATAEN_POLARITY;
+ }
+ if (fb_vm->flag & FB_FLAG_PIXDATA_POSEDGE)
+ ldi |= LDI_PIXELCLK_POLARITY;
+ if (fb_vm->flag & FB_FLAG_PIXDATA_NEGEDGE)
+ ldi &= ~LDI_PIXELCLK_POLARITY;
+ writel_relaxed(ldi, base + LDI_PLR_CTRL);
+ /* always set color mode & shutdown high active */
+ writel_relaxed(dpi, info->reg_base + DSI_DPI_CFG);
+}
+
+static void set_screen_dimensions(struct fb_info *fb)
+{
+ struct fb_var_screeninfo *var = &fb->var;
+ struct hi3620fb_info *info = fb->par;
+ void __iomem *base = info->reg_base;
+ u32 data;
+
+ data = (var->left_margin & 0xfff) << 20;
+ data |= var->right_margin & 0xfff;
+ writel_relaxed(data, base + LDI_HRZ_CTRL0);
+ data = (var->hsync_len - 1) & 0xfff;
+ writel_relaxed(data, base + LDI_HRZ_CTRL1);
+ data = (var->upper_margin & 0xfff) << 20;
+ data |= var->lower_margin & 0xfff;
+ writel_relaxed(data, base + LDI_VRT_CTRL0);
+ data = (var->vsync_len - 1) & 0xfff;
+ writel_relaxed(data, base + LDI_VRT_CTRL1);
+
+ data = (var->xres - 1) & 0xfff;
+ data |= ((var->yres - 1) & 0xfff) << 20;
+ writel_relaxed(data, base + LDI_DSP_SIZE);
+
+ data = (var->yres - 1) & 0xfff;
+ data |= ((var->xres - 1) & 0xfff) << 16;
+ writel_relaxed(data, base + EDC_DISP_SIZE);
+
+ data = (fb->var.xres_virtual - 1) << 16 | (fb->var.yres_virtual - 1);
+ writel_relaxed(data, base + EDC_VIDEO_CHAN_SIZE);
+}
+
+static void set_graphics_start(struct fb_info *fb, int xoffs, int yoffs)
+{
+ struct hi3620fb_info *info = fb->par;
+ struct fb_var_screeninfo *var = &fb->var;
+ void __iomem *base = info->reg_base;
+ u32 addr, data;
+
+ if (yoffs >= var->yres)
+ data = (yoffs - var->yres) & 0xfff;
+ else
+ data = yoffs & 0xfff;
+ data |= (xoffs & 0xfff) << 16;
+ writel_relaxed(data, base + EDC_VIDEO_CHAN_XY);
+ /* setup dma address */
+ addr = (yoffs * var->xres_virtual + xoffs) * var->bits_per_pixel / 8;
+ addr = ALIGN(addr + fb->fix.smem_start, 64);
+ writel_relaxed(addr, base + EDC_VIDEO_CHAN_ADDR);
+}
+
+static void set_dma_control(struct fb_info *fb)
+{
+ struct hi3620fb_info *info = fb->par;
+ void __iomem *base = info->reg_base;
+ unsigned int data;
+
+ /* setup dma stride */
+ writel_relaxed(fb->fix.line_length, base + EDC_VIDEO_CHAN_STRIDE);
+
+ /* setup outstanding */
+ data = readl_relaxed(base + EDC_DISP_CTL);
+ data &= ~(0xf << 26);
+ data |= (8 << 26);
+ writel_relaxed(data, base + EDC_DISP_CTL);
+}
+
+static void set_color(struct fb_info *fb)
+{
+ struct fb_var_screeninfo *var = &fb->var;
+ struct hi3620fb_info *info = fb->par;
+ void __iomem *base = info->reg_base;
+ unsigned int ctrl = 0;
+
+ ctrl = readl_relaxed(base + EDC_VIDEO_CHAN_CTRL);
+ if (var->blue.offset)
+ ctrl |= EDC_CHAN_CTRL_BGR; /* BGR format */
+ ctrl &= ~(7 << 16);
+ switch (info->pix_fmt) {
+ case IMG_PIXEL_FORMAT_ARGB1555:
+ case IMG_PIXEL_FORMAT_RGB555:
+ break;
+ case IMG_PIXEL_FORMAT_RGB565:
+ ctrl |= 1 << 16;
+ break;
+ case IMG_PIXEL_FORMAT_RGB888:
+ ctrl |= 2 << 16;
+ break;
+ case IMG_PIXEL_FORMAT_ARGB8888:
+ ctrl |= 3 << 16;
+ break;
+ }
+ writel_relaxed(ctrl, base + EDC_VIDEO_CHAN_CTRL);
+ ctrl = readl_relaxed(base + EDC_DISP_CTL);
+ ctrl &= ~(3 << 6);
+ switch (info->pix_fmt) {
+ case IMG_PIXEL_FORMAT_ARGB1555:
+ case IMG_PIXEL_FORMAT_RGB555:
+ case IMG_PIXEL_FORMAT_RGB565:
+ break;
+ case IMG_PIXEL_FORMAT_RGB888:
+ case IMG_PIXEL_FORMAT_ARGB8888:
+ ctrl |= 2 << 6;
+ break;
+ }
+ writel_relaxed(ctrl, base + EDC_DISP_CTL);
+ ctrl = readl_relaxed(base + LDI_CTRL);
+ ctrl &= ~(3 << 3);
+ switch (info->pix_fmt) {
+ case IMG_PIXEL_FORMAT_ARGB1555:
+ case IMG_PIXEL_FORMAT_RGB555:
+ case IMG_PIXEL_FORMAT_RGB565:
+ break;
+ case IMG_PIXEL_FORMAT_RGB888:
+ case IMG_PIXEL_FORMAT_ARGB8888:
+ ctrl |= 2 << 3;
+ break;
+ }
+ writel_relaxed(ctrl, base + LDI_CTRL);
+ ctrl = readl_relaxed(base + DSI_DPI_CFG);
+ ctrl &= ~(7 << 2);
+ switch (info->pix_fmt) {
+ case IMG_PIXEL_FORMAT_ARGB1555:
+ case IMG_PIXEL_FORMAT_RGB555:
+ case IMG_PIXEL_FORMAT_RGB565:
+ break;
+ case IMG_PIXEL_FORMAT_RGB888:
+ case IMG_PIXEL_FORMAT_ARGB8888:
+ ctrl |= 5 << 2;
+ break;
+ }
+ writel_relaxed(ctrl, base + DSI_DPI_CFG);
+}
+
+static int hi3620fb_set_par(struct fb_info *fb)
+{
+ struct fb_var_screeninfo *var = &fb->var;
+ struct hi3620fb_info *info = fb->par;
+ void __iomem *base = info->reg_base;
+ unsigned int ctrl = 0;
+
+ fb->fix.ypanstep = var->yres;
+
+ ctrl = readl_relaxed(base + EDC_VIDEO_CHAN_CTRL);
+ ctrl |= EDC_VIDEO_CHAN_CTRL_EN;
+ writel_relaxed(ctrl, base + EDC_VIDEO_CHAN_CTRL);
+
+ set_color(fb);
+ set_panel_control(fb);
+ set_screen_dimensions(fb);
+ set_dma_control(fb);
+ update_edc(base);
+ return 0;
+}
+
+static int hi3620fb_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *fb)
+{
+ struct hi3620fb_info *info = fb->par;
+ void __iomem *base = info->reg_base;
+
+ set_graphics_start(fb, var->xoffset, var->yoffset);
+ update_edc(base);
+ return 0;
+}
+
+static int hi3620fb_blank(int blank_mode, struct fb_info *info)
+{
+ return 0;
+}
+
+static int hi3620fb_ioctl(struct fb_info *fb, unsigned int cmd,
+ unsigned long arg)
+{
+ struct hi3620fb_info *info = fb->par;
+ u32 count = 0, status = 0, mask = 0;
+ int ret = 0;
+
+ switch (cmd) {
+ case FBIO_WAITFORVSYNC:
+ count = info->vsync_cnt;
+
+ /* clear interrupt status of End of Frame */
+ status = readl_relaxed(info->reg_base + EDC_INTS);
+ status &= ~EDC_INT_BAS_END;
+ writel_relaxed(status, info->reg_base + EDC_INTS);
+ /* unmask interrupt of End of Frame */
+ mask = readl_relaxed(info->reg_base + EDC_INTE);
+ mask &= ~EDC_INT_BAS_END;
+ writel_relaxed(mask, info->reg_base + EDC_INTE);
+
+ ret = wait_event_interruptible_timeout(info->wait_vsync,
+ count != info->vsync_cnt,
+ HZ / 10);
+ if (ret < 0)
+ return ret;
+ /* mask interrupt of End of Frame */
+ mask |= EDC_INT_BAS_END;
+ writel_relaxed(mask, info->reg_base + EDC_INTE);
+ break;
+ }
+ return 0;
+}
+
+static struct fb_ops hi3620fb_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = hi3620fb_check_var,
+ .fb_set_par = hi3620fb_set_par,
+ .fb_pan_display = hi3620fb_pan_display,
+ .fb_blank = hi3620fb_blank,
+ .fb_ioctl = hi3620fb_ioctl,
+ .fb_compat_ioctl = hi3620fb_ioctl,
+};
+
+static int hi3620_parse_dt(struct device_node *np, struct hi3620fb_info *info)
+{
+ const char *name;
+ int ret;
+
+ ret = of_property_read_u32(np, "hisilicon,dsi-clock-frequency",
+ &info->dsi_rate);
+ if (ret)
+ return ret;
+ ret = of_property_read_string(np, "hisilicon,mipi-mode", &name);
+ if (ret < 0)
+ return ret;
+ info->mipi_mode_name = kstrdup(name, GFP_KERNEL);
+ ret = of_property_read_u32(np, "hisilicon,mipi-lanes", &info->lane_cnt);
+ if (ret < 0)
+ return ret;
+ ret = of_property_read_u32(np, "hisilicon,color-mode", &info->color_mode);
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+static int hi3620_init_mode(struct device_node *np, struct fb_info *fb)
+{
+ struct fb_fix_screeninfo *fix = &fb->fix;
+ struct fb_var_screeninfo *var = &fb->var;
+ struct display_timings *disp;
+ struct fb_videomode *fb_vm;
+ struct hi3620fb_info *info = fb->par;
+ const char *pix_name;
+ int ret = 0, pix_fmt, i, length;
+
+ fb_vm = kzalloc(sizeof(*fb_vm), GFP_KERNEL);
+ if (!fb_vm)
+ return -ENOMEM;
+ fb->mode = fb_vm;
+ disp = of_get_display_timings(np);
+ if (!disp)
+ return -ENOENT;
+ /* How to handle multiple display timings ???,
+ * add_videomode is implemented by register_framebuffer() */
+ for (i = 0; i < disp->num_timings; i++) {
+ ret = of_get_fb_videomode(np, fb_vm, i);
+ if (ret)
+ goto out;
+ ret = of_property_read_string(np, "hisilicon,pixel-format",
+ &pix_name);
+ if (ret)
+ goto out;
+ if (!strncmp(pix_name, "RGBA8888", 8))
+ pix_fmt = IMG_PIXEL_FORMAT_ARGB8888;
+ else if (!strncmp(pix_name, "RGBX8888", 8))
+ pix_fmt = IMG_PIXEL_FORMAT_RGB888;
+ else if (!strncmp(pix_name, "RGBA5551", 8))
+ pix_fmt = IMG_PIXEL_FORMAT_ARGB1555;
+ else if (!strncmp(pix_name, "RGBX5551", 8))
+ pix_fmt = IMG_PIXEL_FORMAT_RGB555;
+ else if (!strncmp(pix_name, "RGB565", 6))
+ pix_fmt = IMG_PIXEL_FORMAT_RGB565;
+ else {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ set_pix_fmt(info, pix_fmt);
+ fb_videomode_to_var(var, fb_vm);
+ var->xres_virtual = fb_vm->xres;
+ var->yres_virtual = fb_vm->yres * 2; /* double buffering */
+ var->grayscale = 0;
+ var->accel_flags = FB_ACCEL_NONE;
+ /* Now assume that video mode is only 1 in DTS. */
+ //fb_add_videomode(&vm, &fb->modelist);
+ }
+ of_display_timings_exist(np);
+
+ fix->type_aux = 0;
+ fix->type = FB_TYPE_PACKED_PIXELS;
+ fix->visual = FB_VISUAL_TRUECOLOR;
+ fix->xpanstep = 1;
+ fix->ypanstep = 1;
+ fix->ywrapstep = 0;
+ fix->mmio_start = 0; /* No MMIO address */
+ fix->mmio_len = 0; /* No MMIO address */
+ fix->accel = FB_ACCEL_NONE; /* No hardware accelerator */
+
+ length = var->xres_virtual * var->bits_per_pixel / 8;
+ fb->fix.line_length = length;
+ fb->fix.smem_len = ALIGN(fb->fix.line_length * fb->var.yres_virtual,
+ PAGE_SIZE);
+ hi3620_parse_dt(np, info);
+out:
+ return ret;
+}
+
+static irqreturn_t edc_irq_handler(int irq, void *data)
+{
+ struct hi3620fb_info *info = data;
+ u32 status;
+
+ /* clear masked interrupts */
+ status = readl_relaxed(info->reg_base + EDC_INTS);
+ status &= ~readl_relaxed(info->reg_base + EDC_INTE) & 0x3ffff;
+
+ if (status & EDC_INT_BAS_END) {
+ status &= ~EDC_INT_BAS_END;
+ info->vsync_cnt++;
+ wake_up_interruptible(&info->wait_vsync);
+ }
+ writel_relaxed(status, info->reg_base + EDC_INTS);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t ldi_irq_handler(int irq, void *data)
+{
+ struct hi3620fb_info *info = data;
+ u32 value;
+
+ value = readl_relaxed(info->reg_base + LDI_ORG_INT);
+ writel_relaxed(value, info->reg_base + LDI_INT_CLR);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t dsi_irq_handler(int irq, void *data)
+{
+ return IRQ_HANDLED;
+}
+
+static int hi3620_fb_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct hi3620fb_info *info;
+ struct resource *res;
+ struct fb_info *fb;
+ int ret;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "no memory resource defined\n");
+ return -ENODEV;
+ }
+
+ fb = framebuffer_alloc(sizeof(*info), dev);
+ if (!fb) {
+ dev_err(dev, "failed to allocate framebuffer\n");
+ return -ENOMEM;
+ }
+ fb->dev = &pdev->dev;
+ info = fb->par;
+ info->fb = fb;
+ info->dev = &pdev->dev;
+ info->irq_edc = platform_get_irq_byname(pdev, "edc");
+ if (info->irq_edc < 0) {
+ ret = -ENOENT;
+ goto err_fb;
+ }
+ info->irq_ldi = platform_get_irq_byname(pdev, "ldi");
+ if (info->irq_ldi < 0) {
+ ret = -ENOENT;
+ goto err_fb;
+ }
+ info->irq_dsi = platform_get_irq_byname(pdev, "dsi");
+ if (info->irq_dsi < 0) {
+ ret = -ENOENT;
+ goto err_fb;
+ }
+
+ info->reg_base = devm_request_and_ioremap(&pdev->dev, res);
+ if (!info->reg_base) {
+ ret = -EADDRNOTAVAIL;
+ goto err_fb;
+ }
+ info->vedc = devm_regulator_get(dev, "vedc");
+ if (IS_ERR_OR_NULL(info->vedc)) {
+ if (IS_ERR(info->vedc)) {
+ dev_err(dev, "failed to get vedc regulator\n");
+ info->vedc = NULL;
+ }
+ }
+ info->clk_ldi = of_clk_get_by_name(np, "ldi");
+ if (IS_ERR(info->clk_ldi)) {
+ dev_err(dev, "failed to get ldi clock\n");
+ ret = PTR_ERR(info->clk_ldi);
+ goto err_fb;
+ }
+ info->clk_edc = of_clk_get_by_name(np, "edc");
+ if (IS_ERR(info->clk_edc)) {
+ dev_err(dev, "failed to get edc clock\n");
+ ret = PTR_ERR(info->clk_edc);
+ goto err_fb;
+ }
+ info->clk_dsi = of_clk_get_by_name(np, "dsi");
+ if (IS_ERR(info->clk_dsi)) {
+ dev_err(dev, "failed to get dsi clock\n");
+ ret = PTR_ERR(info->clk_dsi);
+ goto err_clk;
+ }
+ if (info->vedc)
+ regulator_enable(info->vedc);
+ clk_prepare_enable(info->clk_ldi);
+ //clk_prepare_enable(info->clk_edc); /* debug for keep display on after boot */
+
+ fb->fbops = &hi3620fb_ops;
+ fb->pseudo_palette = &hi3620fb_pseudo_palette;
+
+ ret = hi3620_init_mode(np, fb);
+ if (ret)
+ goto err_clk;
+
+#if 1
+ fb->screen_base = dma_alloc_coherent(fb->dev, fb->fix.smem_len,
+ &info->fb_start_dma,
+ GFP_KERNEL);
+ if (!fb->screen_base) {
+ dev_err(dev, "failed to allocate memory\n");
+ return -ENOMEM;
+ }
+ fb->screen_size = fb->fix.smem_len;
+ fb->fix.smem_start = info->fb_start_dma;
+#else
+ /* debug for remapping the display region in bootloader */
+ info->fb_start_dma = PAGE_ALIGN(0x35b00130 + 0x40000000);
+ fb->fix.smem_start = info->fb_start_dma;
+ fb->screen_size = fb->fix.smem_len;
+ fb->screen_base = __va(info->fb_start_dma);
+#endif
+ platform_set_drvdata(pdev, info);
+
+ disable_edc(info->reg_base);
+ hi3620_mipi_init(dev);
+ hi3620_mipi_enable(dev);
+ set_graphics_start(fb, 0, 0);
+ hi3620fb_set_par(fb);
+
+
+ /* clear IRQ status & enable IRQ */
+ writel_relaxed(0, info->reg_base + EDC_INTS);
+ /* enable interrupts of bus error */
+ writel_relaxed(0x2ff, info->reg_base + EDC_INTE);
+ writel_relaxed(0x4, info->reg_base + LDI_INT_EN); /* disable front porch int for debugging */
+ writel_relaxed(0x3fff, info->reg_base + LDI_INT_CLR);
+
+ enable_edc(info->reg_base);
+
+ ret = devm_request_irq(dev, info->irq_edc, edc_irq_handler,
+ IRQF_DISABLED, "edc", info);
+ if (ret < 0) {
+ dev_err(dev, "failed to request edc irq\n");
+ goto err_clk;
+ }
+ ret = devm_request_irq(dev, info->irq_ldi, ldi_irq_handler,
+ IRQF_DISABLED, "ldi", info);
+ if (ret < 0) {
+ dev_err(dev, "failed to request ldi irq\n");
+ goto err_clk;
+ }
+#if 0
+ ret = devm_request_irq(dev, info->irq_dsi, dsi_irq_handler,
+ IRQF_DISABLED, "dsi", info);
+ if (ret < 0) {
+ dev_err(dev, "failed to request dsi irq\n");
+ goto err_clk;
+ }
+#endif
+ ret = register_framebuffer(fb);
+ if (ret < 0) {
+ dev_err(dev, "failed to register hi3620 framebuffer\n");
+ goto err_clk;
+ }
+ init_waitqueue_head(&info->wait_vsync);
+ /* clock rate of ldi */
+
+ return 0;
+err_clk:
+ clk_disable_unprepare(info->clk_edc);
+ clk_disable_unprepare(info->clk_ldi);
+err_fb:
+ framebuffer_release(fb);
+ return ret;
+}
+
+static int hi3620_fb_remove(struct platform_device *pdev)
+{
+ hi3620_mipi_disable(&pdev->dev);
+ return 0;
+}
+
+static void dump_reg(void __iomem *base, int offset, int size)
+{
+ int i;
+ for (i = 0; i < size; i += 4) {
+ pr_err("#[0x%x]:0x%x\n", (int)base + offset + i, readl_relaxed(base + offset + i));
+ }
+}
+
+static int dsi_init(void __iomem *base)
+{
+ writel_relaxed(1, base + DSI_PWR_UP);
+ writel_relaxed(7, base + DSI_PHY_RSTZ);
+ return 0;
+}
+
+static int hi3620_fb_suspend(struct device *dev)
+{
+ unsigned int data;
+ struct hi3620fb_info *info = dev_get_drvdata(dev);
+ void __iomem *base = info->reg_base;
+
+ dsi_enter_sleep();
+
+ info->graph_chan_addr = readl_relaxed(base + EDC_GRAPH_CHAN_ADDR);
+ info->video_chan_addr = readl_relaxed(base + EDC_VIDEO_CHAN_ADDR);
+ info->graph_chan_stride = readl_relaxed(base + EDC_GRAPH_CHAN_STRIDE);
+ info->video_chan_stride = readl_relaxed(base + EDC_VIDEO_CHAN_STRIDE);
+ info->graph_chan_xy = readl_relaxed(base + EDC_GRAPH_CHAN_XY);
+ info->video_chan_xy = readl_relaxed(base + EDC_VIDEO_CHAN_XY);
+ info->graph_chan_size = readl_relaxed(base + EDC_GRAPH_CHAN_SIZE);
+ info->video_chan_size = readl_relaxed(base + EDC_VIDEO_CHAN_SIZE);
+
+ info->edc_disp_size = readl_relaxed(base + EDC_DISP_SIZE);
+ info->edc_disp_dpd = readl_relaxed(base + EDC_DISP_DPD);
+ info->ldi_hrz_ctrl0 = readl_relaxed(base + LDI_HRZ_CTRL0);
+ info->ldi_hrz_ctrl1 = readl_relaxed(base + LDI_HRZ_CTRL1);
+ info->ldi_vrt_ctrl0 = readl_relaxed(base + LDI_VRT_CTRL0);
+ info->ldi_vrt_ctrl1 = readl_relaxed(base + LDI_VRT_CTRL1);
+ info->ldi_plr_ctrl = readl_relaxed(base + LDI_PLR_CTRL);
+ info->ldi_dsp_size = readl_relaxed(base + LDI_DSP_SIZE);
+ info->ldi_ctrl = readl_relaxed(base + LDI_CTRL);
+ info->ldi_inte = readl_relaxed(base + LDI_INT_EN);
+ info->dsi_cmd_mod_ctrl = readl_relaxed(base + DSI_CMD_MOD_CTRL);
+ info->dsi_te_ctrl = readl_relaxed(base + DSI_TE_CTRL);
+ info->dsi_te_hs_num = readl_relaxed(base + DSI_TE_HS_NUM);
+ info->dsi_te_hs_wd = readl_relaxed(base + DSI_TE_HS_WD);
+ info->dsi_te_vs_wd = readl_relaxed(base + DSI_TE_VS_WD);
+ info->clkmgr_cfg = readl_relaxed(base + DSI_CLKMGR_CFG);
+ info->dpi_cfg = readl_relaxed(base + DSI_DPI_CFG);
+ info->pckhdl_cfg = readl_relaxed(base + DSI_PCKHDL_CFG);
+ info->vid_mode_cfg = readl_relaxed(base + DSI_VID_MODE_CFG);
+ info->vid_pkt_cfg = readl_relaxed(base + DSI_VID_PKT_CFG);
+ info->cmd_mode_cfg = readl_relaxed(base + DSI_CMD_MODE_CFG);
+ info->tmr_line_cfg = readl_relaxed(base + DSI_TMR_LINE_CFG);
+ info->vtiming_cfg = readl_relaxed(base + DSI_VTIMING_CFG);
+ info->to_cnt_cfg = readl_relaxed(base + DSI_TO_CNT_CFG);
+ info->phy_if_cfg = readl_relaxed(base + DSI_PHY_IF_CFG);
+ info->phy_if_ctrl = readl_relaxed(base + DSI_PHY_IF_CTRL);
+ info->edpi_cfg = readl_relaxed(base + DSI_EDPI_CFG);
+ info->lpcmd_time = readl_relaxed(base + DSI_LPCMD_TIME);
+
+ /* disable channel */
+ data = readl_relaxed(base + EDC_GRAPH_CHAN_CTRL);
+ info->graph_chan_ctrl = data;
+ data &= ~EDC_GRAPH_CHAN_CTRL_EN;
+ writel_relaxed(data, base + EDC_GRAPH_CHAN_CTRL);
+ data = readl_relaxed(base + EDC_VIDEO_CHAN_CTRL);
+ info->video_chan_ctrl = data;
+ data &= ~EDC_VIDEO_CHAN_CTRL_EN;
+ writel_relaxed(data, base + EDC_VIDEO_CHAN_CTRL);
+
+ /* disable all EDC interrupts */
+ info->edc_inte = readl_relaxed(base + EDC_INTE);
+ writel_relaxed(0xffffffff, base + EDC_INTE);
+ /* clear EDC interrupt status */
+ writel_relaxed(0, base + EDC_INTS);
+
+ /* disable EDC */
+ data = readl_relaxed(base + EDC_DISP_CTL);
+ info->edc_disp_ctrl = data;
+ data &= ~EDC_CTRL_EN;
+ writel_relaxed(data, base + EDC_DISP_CTL);
+ update_edc(base);
+ return 0;
+}
+
+static int hi3620_fb_resume(struct device *dev)
+{
+ struct hi3620fb_info *info = dev_get_drvdata(dev);
+ void __iomem *base = info->reg_base;
+
+ dsi_init(base);
+ hi3620_mipi_enable(info->dev);
+ writel_relaxed(info->clkmgr_cfg, base + DSI_CLKMGR_CFG);
+ set_graphics_start(info->fb, 0, 0);
+ hi3620fb_set_par(info->fb);
+ writel_relaxed(info->ldi_inte, base + LDI_INT_EN);
+ writel_relaxed(0x3fff, info->reg_base + LDI_INT_CLR);
+
+ /* clear EDC interrupt status */
+ writel_relaxed(0, base + EDC_INTS);
+ /* enable all EDC interrupts */
+ writel_relaxed(info->edc_inte, base + EDC_INTE);
+
+ writel_relaxed(info->ldi_ctrl, base + LDI_CTRL);
+
+ enable_edc(base);
+
+ /* enable channel */
+ writel_relaxed(info->graph_chan_ctrl,
+ base + EDC_GRAPH_CHAN_CTRL);
+ writel_relaxed(info->video_chan_ctrl,
+ base + EDC_VIDEO_CHAN_CTRL);
+
+ dsi_exit_sleep();
+
+ return 0;
+}
+
+static const struct dev_pm_ops hi3620_fb_pm_ops = {
+ .suspend = hi3620_fb_suspend,
+ .resume = hi3620_fb_resume,
+};
+
+static const struct of_device_id hi3620_fb_of_match[] = {
+ { .compatible = "hisilicon,hi3620-fb", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, hi3620_fb_of_match);
+
+static struct platform_driver hi3620_fb_driver = {
+ .probe = hi3620_fb_probe,
+ .remove = hi3620_fb_remove,
+ .driver = {
+ .name = "hi3620-fb",
+ .owner = THIS_MODULE,
+ .pm = &hi3620_fb_pm_ops,
+ .of_match_table = hi3620_fb_of_match,
+ },
+};
+module_platform_driver(hi3620_fb_driver);
diff --git a/drivers/video/hisilicon/hi3620_fb.h b/drivers/video/hisilicon/hi3620_fb.h
new file mode 100644
index 000000000000..213d0695a8ab
--- /dev/null
+++ b/drivers/video/hisilicon/hi3620_fb.h
@@ -0,0 +1,208 @@
+#ifndef __HI3620FB_H
+#define __HI3620FB_H
+
+#define EDC_ID 0x000
+
+/* Channel 1 */
+#define EDC_GRAPH_CHAN_ADDR 0x004
+#define EDC_GRAPH_CHAN_STRIDE 0x00c
+#define EDC_GRAPH_CHAN_XY 0x010
+#define EDC_GRAPH_CHAN_SIZE 0x014
+#define EDC_GRAPH_CHAN_CTRL 0x018
+#define EDC_GRAPH_CHAN_CKEY_MIN 0x01c
+#define EDC_GRAPH_CHAN_CKEY_MAX 0x020
+
+/* Channel 2 */
+#define EDC_VIDEO_CHAN_ADDR 0x024
+#define EDC_VIDEO_CHAN_STRIDE 0x02c
+#define EDC_VIDEO_CHAN_XY 0x030
+#define EDC_VIDEO_CHAN_SIZE 0x034
+#define EDC_VIDEO_CHAN_CTRL 0x038
+#define EDC_VIDEO_CHAN_CKEY_MIN 0x03c
+#define EDC_VIDEO_CHAN_CKEY_MAX 0x040
+
+#define EDC_GRAPH_CHAN_CTRL_EN (1 << 24)
+#define EDC_VIDEO_CHAN_CTRL_EN (1 << 22)
+#define EDC_CHAN_CTRL_BGR (1 << 19)
+
+#define EDC_DISP_SIZE 0x090
+#define EDC_DISP_CTL 0x094
+#define EDC_DISP_DPD 0x098
+#define EDC_STS 0x09c
+#define EDC_INTS 0x0a0
+#define EDC_INTE 0x0a4
+
+#define LDI_HRZ_CTRL0 0x800
+#define LDI_HRZ_CTRL1 0x804
+#define LDI_VRT_CTRL0 0x808
+#define LDI_VRT_CTRL1 0x80c
+#define LDI_PLR_CTRL 0x810
+#define LDI_DSP_SIZE 0x814
+#define LDI_INT_EN 0x81c
+#define LDI_CTRL 0x820
+#define LDI_ORG_INT 0x824
+#define LDI_MSK_INT 0x828
+#define LDI_INT_CLR 0x82c
+#define LDI_WORK_MODE 0x830
+#define LDI_HDMI_DSI_GT 0x834
+
+#define DSI_CMD_MOD_CTRL 0x83c
+#define DSI_TE_CTRL 0x840
+#define DSI_TE_HS_NUM 0x844
+#define DSI_TE_HS_WD 0x848
+#define DSI_TE_VS_WD 0x84c
+
+#define DSI_PWR_UP 0x904
+#define DSI_CLKMGR_CFG 0x908
+#define DSI_DPI_CFG 0x90c
+#define DSI_PCKHDL_CFG 0x918
+#define DSI_VID_MODE_CFG 0x91c
+#define DSI_VID_PKT_CFG 0x920
+#define DSI_CMD_MODE_CFG 0x924
+#define DSI_TMR_LINE_CFG 0x928
+#define DSI_VTIMING_CFG 0x92c
+#define DSI_PHY_TMR_CFG 0x930
+#define DSI_GEN_HDR 0x934
+#define DSI_GEN_PLD_DATA 0x938
+#define DSI_CMD_PKT_STATUS 0x93c
+#define DSI_TO_CNT_CFG 0x940
+#define DSI_ERROR_ST0 0x944
+#define DSI_ERROR_ST1 0x948
+#define DSI_ERROR_MSK0 0x94c
+#define DSI_ERROR_MSK1 0x950
+#define DSI_PHY_RSTZ 0x954
+#define DSI_PHY_IF_CFG 0x958
+#define DSI_PHY_IF_CTRL 0x95c
+#define DSI_PHY_STATUS 0x960
+#define DSI_PHY_TST_CTRL0 0x964
+#define DSI_PHY_TST_CTRL1 0x968
+#define DSI_EDPI_CFG 0x96c
+#define DSI_LPCMD_TIME 0x970
+
+/* bits field of DSI_CMD_PKT_STATUS register */
+#define GEN_RD_CMD_BUSY (1 << 6)
+#define GEN_PLD_R_FULL (1 << 5)
+#define GEN_PLD_R_EMPTY (1 << 4)
+#define GEN_PLD_W_FULL (1 << 3)
+
+/* bits field of EDC_DISP_CTL register */
+#define EDC_CTRL_CLK_EN (1 << 31)
+#define EDC_CTRL_FRAME_END_START (1 << 30)
+#define EDC_CTRL_EN (1 << 10)
+#define EDC_CTRL_CFG_OK (1 << 1)
+#define EDC_CTRL_CFG_OK_SEL (1 << 0)
+
+/* bits field of EDC_INTS/EDC_INTE register */
+#define EDC_INT_BAS_END (1 << 6)
+
+/* bits field of LDI_CTRL register */
+#define LDI_CTRL_SHUTDOWN (1 << 15)
+#define LDI_CTRL_COLOR_MODE (1 << 14)
+#define LDI_CTRL_BGR (1 << 13)
+#define LDI_CTRL_DATA_GATE_EN (1 << 2)
+#define LDI_CTRL_DISP_MODE (1 << 1)
+#define LDI_CTRL_EN (1 << 0)
+
+/* bits field of LDI_WORK_MODE register */
+#define LDI_WORK_MODE_EN (1 << 0)
+
+/* bits field of LDI_PLT_CTRL register */
+#define LDI_POLARITY_MASK 0xf
+#define LDI_DATAEN_POLARITY (1 << 3)
+#define LDI_PIXELCLK_POLARITY (1 << 2)
+#define LDI_HSYNC_POLARITY (1 << 1)
+#define LDI_VSYNC_POLARITY (1 << 0)
+
+/* bits field of DSI_DPI_CFG register */
+#define DSI_DPI_POLARITY_MASK (0x1f << 5)
+#define DSI_DPI_COLORM_POLARITY (1 << 9)
+#define DSI_DPI_SHUTD_POLARITY (1 << 8)
+#define DSI_DPI_HSYNC_POLARITY (1 << 7)
+#define DSI_DPI_VSYNC_POLARITY (1 << 6)
+#define DSI_DPI_DATAEN_POLARITY (1 << 5)
+
+/* bits field of DSI_PHY_STATUS register */
+#define DSI_PHY_STOP_STATE3_LANE (1 << 12)
+#define DSI_PHY_STOP_STATE2_LANE (1 << 9)
+#define DSI_PHY_STOP_STATE1_LANE (1 << 7)
+#define DSI_PHY_STOP_STATE0_LANE (1 << 4)
+#define DSI_PHY_LOCK (1 << 0)
+
+enum {
+ IMG_PIXEL_FORMAT_ARGB1555 = 0,
+ IMG_PIXEL_FORMAT_RGB555,
+ IMG_PIXEL_FORMAT_RGB565,
+ IMG_PIXEL_FORMAT_RGB888,
+ IMG_PIXEL_FORMAT_ARGB8888,
+};
+
+struct hi3620fb_info {
+ struct fb_info *fb;
+ struct device *dev;
+ void __iomem *reg_base;
+ struct clk *clk_ldi;
+ struct clk *clk_edc;
+ struct clk *clk_dsi;
+ int irq_edc;
+ int irq_ldi;
+ int irq_dsi;
+ struct regulator *vedc;
+ dma_addr_t fb_start_dma;
+ int pix_fmt;
+ int dsi_rate; /* dsi bit clock rate */
+ const char *mipi_mode_name;
+ int lane_cnt;
+ int color_mode;
+ wait_queue_head_t wait_vsync;
+ int vsync_cnt;
+ struct mutex dsi_mutex;
+ unsigned int graph_chan_addr;
+ unsigned int graph_chan_stride;
+ unsigned int graph_chan_xy;
+ unsigned int graph_chan_size;
+ unsigned int graph_chan_ctrl;
+ unsigned int video_chan_addr;
+ unsigned int video_chan_stride;
+ unsigned int video_chan_xy;
+ unsigned int video_chan_size;
+ unsigned int video_chan_ctrl;
+ unsigned int edc_inte;
+ unsigned int edc_disp_size;
+ unsigned int edc_disp_dpd;
+ unsigned int edc_disp_ctrl;
+ unsigned int ldi_hrz_ctrl0;
+ unsigned int ldi_hrz_ctrl1;
+ unsigned int ldi_vrt_ctrl0;
+ unsigned int ldi_vrt_ctrl1;
+ unsigned int ldi_plr_ctrl;
+ unsigned int ldi_dsp_size;
+ unsigned int ldi_inte;
+ unsigned int ldi_ctrl;
+ unsigned int ldi_work_mode;
+ unsigned int ldi_hdmi_dsi_gt;
+ unsigned int dsi_cmd_mod_ctrl;
+ unsigned int dsi_te_ctrl;
+ unsigned int dsi_te_hs_num;
+ unsigned int dsi_te_hs_wd;
+ unsigned int dsi_te_vs_wd;
+ unsigned int clkmgr_cfg;
+ unsigned int dpi_cfg;
+ unsigned int pckhdl_cfg;
+ unsigned int vid_mode_cfg;
+ unsigned int vid_pkt_cfg;
+ unsigned int cmd_mode_cfg;
+ unsigned int tmr_line_cfg;
+ unsigned int vtiming_cfg;
+ unsigned int to_cnt_cfg;
+ unsigned int phy_rstz;
+ unsigned int phy_if_cfg;
+ unsigned int phy_if_ctrl;
+ unsigned int edpi_cfg;
+ unsigned int lpcmd_time;
+};
+
+extern int hi3620_mipi_init(struct device *dev);
+extern int hi3620_mipi_enable(struct device *dev);
+extern int hi3620_mipi_disable(struct device *dev);
+extern int send_generic_packet(u8 *cmd, int len);
+#endif /* __HI3620FB_H */
diff --git a/include/linux/clk-private.h b/include/linux/clk-private.h
index dd7adff76e81..8138c94409f3 100644
--- a/include/linux/clk-private.h
+++ b/include/linux/clk-private.h
@@ -33,8 +33,11 @@ struct clk {
const char **parent_names;
struct clk **parents;
u8 num_parents;
+ u8 new_parent_index;
unsigned long rate;
unsigned long new_rate;
+ struct clk *new_parent;
+ struct clk *new_child;
unsigned long flags;
unsigned int enable_count;
unsigned int prepare_count;
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 11860985fecb..227a20d5b9b2 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -27,6 +27,7 @@
#define CLK_IS_ROOT BIT(4) /* root clk, has no parent */
#define CLK_IS_BASIC BIT(5) /* Basic clk, can't do a to_clk_foo() */
#define CLK_GET_RATE_NOCACHE BIT(6) /* do not use the cached clk rate */
+#define CLK_SET_RATE_NO_REPARENT BIT(7) /* don't re-parent on rate change */
struct clk_hw;
@@ -79,6 +80,10 @@ struct clk_hw;
* @round_rate: Given a target rate as input, returns the closest rate actually
* supported by the clock.
*
+ * @determine_rate: Given a target rate as input, returns the closest rate
+ * actually supported by the clock, and optionally the parent clock
+ * that should be used to provide the clock rate.
+ *
* @get_parent: Queries the hardware to determine the parent of a clock. The
* return value is a u8 which specifies the index corresponding to
* the parent clock. This index can be applied to either the
@@ -126,6 +131,9 @@ struct clk_ops {
unsigned long parent_rate);
long (*round_rate)(struct clk_hw *hw, unsigned long,
unsigned long *);
+ long (*determine_rate)(struct clk_hw *hw, unsigned long rate,
+ unsigned long *best_parent_rate,
+ struct clk **best_parent_clk);
int (*set_parent)(struct clk_hw *hw, u8 index);
u8 (*get_parent)(struct clk_hw *hw);
int (*set_rate)(struct clk_hw *hw, unsigned long,
@@ -210,6 +218,10 @@ void of_fixed_clk_setup(struct device_node *np);
* CLK_GATE_SET_TO_DISABLE - by default this clock sets the bit at bit_idx to
* enable the clock. Setting this flag does the opposite: setting the bit
* disable the clock and clearing it enables the clock
+ * CLK_GATE_HIWORD_MASK - The gate settings are only in lower 16-bit
+ * of this register, and mask of gate bits are in higher 16-bit of this
+ * register. While setting the gate bits, higher 16-bit should also be
+ * updated to indicate changing gate bits.
*/
struct clk_gate {
struct clk_hw hw;
@@ -220,6 +232,7 @@ struct clk_gate {
};
#define CLK_GATE_SET_TO_DISABLE BIT(0)
+#define CLK_GATE_HIWORD_MASK BIT(1)
extern const struct clk_ops clk_gate_ops;
struct clk *clk_register_gate(struct device *dev, const char *name,
@@ -299,6 +312,7 @@ struct clk *clk_register_divider_table(struct device *dev, const char *name,
* Flags:
* CLK_MUX_INDEX_ONE - register index starts at 1, not 0
* CLK_MUX_INDEX_BIT - register index is a single bit (power of two)
+ * CLK_MUX_HIWORD_MASK - register contains high 16-bit as mask field
*/
struct clk_mux {
struct clk_hw hw;
@@ -312,6 +326,7 @@ struct clk_mux {
#define CLK_MUX_INDEX_ONE BIT(0)
#define CLK_MUX_INDEX_BIT BIT(1)
+#define CLK_MUX_HIWORD_MASK BIT(2)
extern const struct clk_ops clk_mux_ops;
@@ -403,6 +418,7 @@ const char *__clk_get_name(struct clk *clk);
struct clk_hw *__clk_get_hw(struct clk *clk);
u8 __clk_get_num_parents(struct clk *clk);
struct clk *__clk_get_parent(struct clk *clk);
+struct clk *clk_get_parent_by_index(struct clk *clk, u8 index);
unsigned int __clk_get_enable_count(struct clk *clk);
unsigned int __clk_get_prepare_count(struct clk *clk);
unsigned long __clk_get_rate(struct clk *clk);
@@ -410,6 +426,9 @@ unsigned long __clk_get_flags(struct clk *clk);
bool __clk_is_prepared(struct clk *clk);
bool __clk_is_enabled(struct clk *clk);
struct clk *__clk_lookup(const char *name);
+long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *best_parent_rate,
+ struct clk **best_parent_p);
/*
* FIXME clock api without lock protection
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index 96d3e4ab11a9..4e1c843895e7 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -1000,6 +1000,7 @@ int dma_async_device_register(struct dma_device *device);
void dma_async_device_unregister(struct dma_device *device);
void dma_run_dependencies(struct dma_async_tx_descriptor *tx);
struct dma_chan *dma_find_channel(enum dma_transaction_type tx_type);
+struct dma_chan *dma_get_slave_channel(struct dma_chan *chan);
struct dma_chan *net_dma_find_channel(void);
#define dma_request_channel(mask, x, y) __dma_request_channel(&(mask), x, y)
#define dma_request_slave_channel_compat(mask, x, y, dev, name) \
diff --git a/include/linux/mfd/hi6421-pmic.h b/include/linux/mfd/hi6421-pmic.h
new file mode 100644
index 000000000000..0b60a9b2a666
--- /dev/null
+++ b/include/linux/mfd/hi6421-pmic.h
@@ -0,0 +1,99 @@
+/*
+ * Header file for device driver Hi6421 PMIC
+ *
+ * Copyright (c) 2013 Linaro Ltd.
+ * Copyright (C) 2011 Hisilicon.
+ *
+ * Guodong Xu <guodong.xu@linaro.org>
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __HI6421_PMIC_H
+#define __HI6421_PMIC_H
+
+#include <linux/irqdomain.h>
+#include <linux/mutex.h>
+#include <linux/time.h>
+
+#define OCP_DEB_CTRL_REG (0x51)
+#define OCP_DEB_SEL_MASK (0x0C)
+#define OCP_DEB_SEL_8MS (0x00)
+#define OCP_DEB_SEL_16MS (0x04)
+#define OCP_DEB_SEL_32MS (0x08)
+#define OCP_DEB_SEL_64MS (0x0C)
+#define OCP_EN_DEBOUNCE_MASK (0x02)
+#define OCP_EN_DEBOUNCE_ENABLE (0x02)
+#define OCP_AUTO_STOP_MASK (0x01)
+#define OCP_AUTO_STOP_ENABLE (0x01)
+#define HI6421_REGS_ENA_PROTECT_TIME (100) /* in microseconds */
+#define HI6421_ECO_MODE_ENABLE (1)
+#define HI6421_ECO_MODE_DISABLE (0)
+
+#define HI6421_NR_IRQ 24
+#define HI6421_MASK_FIELD 0xFF
+#define HI6421_BITS 8
+
+#define HI6421_IRQ_ALARM 0 /* RTC Alarm */
+#define HI6421_IRQ_OTMP 1 /* Temperature too high */
+#define HI6421_IRQ_OCP 2 /* BUCK/LDO overload */
+#define HI6421_IRQ_RESET_IN 3 /* RESETIN_N signal */
+#define HI6421_IRQ_ONKEY_10S 4 /* PWRON key hold for 10s */
+#define HI6421_IRQ_ONKEY_1S 5 /* PWRON key hold for 1s */
+#define HI6421_IRQ_ONKEY_UP 6 /* PWRON key released */
+#define HI6421_IRQ_ONKEY_DOWN 7 /* PWRON key pressed */
+#define HI6421_IRQ_HEADSET_OUT 8 /* Headset plugged out */
+#define HI6421_IRQ_HEADSET_IN 9 /* Headset plugged in */
+#define HI6421_IRQ_COULOMB 10 /* Coulomb Counter */
+#define HI6421_IRQ_VBUS_UP 11 /* VBUS rising */
+#define HI6421_IRQ_VBUS_DOWN 12 /* VBUS falling */
+#define HI6421_IRQ_VBAT_LOW 13 /* VBattery too low */
+#define HI6421_IRQ_VBAT_HIGH 14 /* VBattery overvoltage */
+#define HI6421_IRQ_CHARGE_IN1 15 /* Charger plugged in */
+#define HI6421_IRQ_CHARGE_IN3 16 /* Charger plugged in */
+#define HI6421_IRQ_CHARGE_IN2 17 /* Charger plugged in */
+#define HI6421_IRQ_HS_BTN_DOWN 18 /* Headset button pressed */
+#define HI6421_IRQ_HS_BTN_UP 19 /* Headset button released */
+#define HI6421_IRQ_BATTERY_ON 20 /* Battery inserted */
+#define HI6421_IRQ_RESET 21 /* Reset */
+
+/**
+ * struct hi6421_pmic - Hi6421 PMIC chip-level data structure.
+ *
+ * This struct describes Hi6421 PMIC chip-level data.
+ *
+ * @enable_mutex: Used by regulators, to make sure that only one regulator is
+ * in the turning-on phase at any time. See also @last_enabled
+ * and hi6421_regulator_enable().
+ * @last_enabled: Used by regulators, to make sure enough distance in time
+ * between enabling of any of two regulators.
+ */
+struct hi6421_pmic {
+ struct resource *res;
+ struct device *dev;
+ void __iomem *regs;
+ spinlock_t lock;
+ struct irq_domain *domain;
+ int irq;
+ int gpio;
+ struct mutex enable_mutex;
+ struct timeval last_enabled;
+};
+
+/* Register Access Helpers */
+u32 hi6421_pmic_read(struct hi6421_pmic *pmic, int reg);
+void hi6421_pmic_write(struct hi6421_pmic *pmic, int reg, u32 val);
+void hi6421_pmic_rmw(struct hi6421_pmic *pmic, int reg, u32 mask, u32 bits);
+
+#endif /* __HI6421_PMIC_H */
diff --git a/include/linux/mfd/r63306.h b/include/linux/mfd/r63306.h
new file mode 100644
index 000000000000..c266c99966ad
--- /dev/null
+++ b/include/linux/mfd/r63306.h
@@ -0,0 +1,45 @@
+
+#ifndef __R63306_H
+#define __R63306_H
+
+struct r63306_chip {
+ struct device *dev;
+ struct mutex *lock;
+};
+
+struct r63306_pwm {
+ int divider;
+ int duty_cycle;
+ int pwm_wm;
+};
+
+struct r63306_device_id {
+ int vendor;
+ int product;
+ int revision;
+};
+
+struct r63306_cabc {
+ bool cabc_on;
+ bool pwm_on;
+ bool pfm_on;
+ bool ledpwm_pin;
+ bool ledpwm_pol;
+};
+
+struct r63306_cabc_param {
+ int backlight;
+};
+
+extern int dsi_reset(void);
+extern int dsi_enter_sleep(void);
+extern int dsi_exit_sleep(void);
+extern int dsi_get_pwm(struct r63306_pwm *pwm);
+extern int dsi_set_pwm(struct r63306_pwm *pwm);
+extern int dsi_get_cabc(struct r63306_cabc *cabc);
+extern int dsi_set_cabc(struct r63306_cabc *cabc);
+extern int dsi_get_cabc_param(struct r63306_cabc_param *cabc);
+extern int dsi_set_cabc_param(struct r63306_cabc_param *cabc);
+extern int dsi_get_backlight(int *level);
+
+#endif /* __R63306_H */
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index 39613b9a6fc5..49fb132ab2f7 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -188,6 +188,9 @@ extern int __mmc_claim_host(struct mmc_host *host, atomic_t *abort);
extern void mmc_release_host(struct mmc_host *host);
extern int mmc_try_claim_host(struct mmc_host *host);
+extern void mmc_get_card(struct mmc_card *card);
+extern void mmc_put_card(struct mmc_card *card);
+
extern int mmc_flush_cache(struct mmc_card *);
extern int mmc_detect_card_removed(struct mmc_host *host);
diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
index 198f0fa44e9f..3e6b68620473 100644
--- a/include/linux/mmc/dw_mmc.h
+++ b/include/linux/mmc/dw_mmc.h
@@ -185,6 +185,7 @@ struct dw_mci {
u32 quirks;
struct regulator *vmmc; /* Power regulator */
+ struct regulator *vqmmc; /* Signaling regulator (vccq) */
unsigned long irq_flags; /* IRQ flags */
int irq;
};
@@ -246,7 +247,7 @@ struct dw_mci_board {
int (*init)(u32 slot_id, irq_handler_t , void *);
int (*get_ro)(u32 slot_id);
- int (*get_cd)(u32 slot_id);
+ int (*get_cd)(struct dw_mci *host, u32 slot_id);
int (*get_ocr)(u32 slot_id);
int (*get_bus_wd)(u32 slot_id);
/*
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 66b465927602..5621c9c581d3 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -240,7 +240,7 @@ struct mmc_host {
#define MMC_CAP_SPI (1 << 4) /* Talks only SPI protocols */
#define MMC_CAP_NEEDS_POLL (1 << 5) /* Needs polling for card-detection */
#define MMC_CAP_8_BIT_DATA (1 << 6) /* Can the host do 8 bit transfers */
-
+#define MMC_CAP_AGGRESSIVE_PM (1 << 7) /* Suspend (e)MMC/SD at idle */
#define MMC_CAP_NONREMOVABLE (1 << 8) /* Nonremovable e.g. eMMC */
#define MMC_CAP_WAIT_WHILE_BUSY (1 << 9) /* Waits while card is busy */
#define MMC_CAP_ERASE (1 << 10) /* Allow erase/trim commands */
diff --git a/include/linux/nmi.h b/include/linux/nmi.h
index c8f8aa0383e5..db50840e6355 100644
--- a/include/linux/nmi.h
+++ b/include/linux/nmi.h
@@ -14,11 +14,8 @@
* may be used to reset the timeout - for code which intentionally
* disables interrupts for a long time. This call is stateless.
*/
-#if defined(CONFIG_HAVE_NMI_WATCHDOG) || defined(CONFIG_HARDLOCKUP_DETECTOR_NMI)
-#include <asm/nmi.h>
-#endif
-
#if defined(CONFIG_HAVE_NMI_WATCHDOG) || defined(CONFIG_HARDLOCKUP_DETECTOR)
+#include <asm/nmi.h>
extern void touch_nmi_watchdog(void);
#else
static inline void touch_nmi_watchdog(void)
diff --git a/include/linux/platform_data/hi3620-dsi.h b/include/linux/platform_data/hi3620-dsi.h
new file mode 100644
index 000000000000..ebc141cf482a
--- /dev/null
+++ b/include/linux/platform_data/hi3620-dsi.h
@@ -0,0 +1,53 @@
+/*
+ * Hisilicon Hi3620 MIPI DSI head file
+ *
+ * Copyright (c) 2013 Hisilicon Limited.
+ * Copyright (c) 2013 Linaro Limited.
+ *
+ * Author: Haojian Zhuang <haojian.zhuang@linaro.org>
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#ifndef __HI3620_DSI_H
+#define __HI3620_DSI_H
+
+enum DATA_TYPE {
+ GEN_SHORT_WR_PARAM0 = 0x03,
+ GEN_SHORT_WR_PARAM1 = 0x13,
+ GEN_SHORT_WR_PARAM2 = 0x23,
+ GEN_RD_PARAM0 = 0x04,
+ GEN_RD_PARAM1 = 0x14,
+ GEN_RD_PARAM2 = 0x24,
+ DCS_SHORT_WR_PARAM0 = 0x05,
+ DCS_SHORT_WR_PARAM1 = 0x15,
+ DCS_RD_PARAM0 = 0x06,
+ SET_MAX_PKT = 0x37,
+ NULL_PKT = 0x09,
+ BLANKING_PKT = 0x19,
+ GEN_LONG_WR = 0x29,
+ DCS_LONG_WR = 0x39,
+ PACKED_PIXEL_16B = 0x0e,
+ PACKED_PIXEL_18B = 0x1e,
+ LOOSELY_PACKED_PIXEL_18B = 0x2e,
+ PACKED_PIXEL_24B = 0x3e,
+};
+
+int hi3620_dsi_phy_write(void __iomem *reg_base, unsigned char addr,
+ unsigned char data);
+unsigned char hi3620_dsi_phy_read(void __iomem *reg_base, unsigned char addr);
+
+#endif
diff --git a/include/uapi/linux/fb.h b/include/uapi/linux/fb.h
index fb795c3b3c17..864e01e9613c 100644
--- a/include/uapi/linux/fb.h
+++ b/include/uapi/linux/fb.h
@@ -226,6 +226,11 @@ struct fb_bitfield {
#define FB_VMODE_SMOOTH_XPAN 512 /* smooth xpan possible (internally used) */
#define FB_VMODE_CONUPDATE 512 /* don't update x/yoffset */
+#define FB_FLAG_DE_HIGH 1 /* data enable high active */
+#define FB_FLAG_DE_LOW 2 /* data enable low active */
+#define FB_FLAG_PIXDATA_POSEDGE 4 /* pixdata postive edge */
+#define FB_FLAG_PIXDATA_NEGEDGE 8 /* pixdata negative edge */
+
/*
* Display rotation support
*/
diff --git a/kernel/watchdog.c b/kernel/watchdog.c
index e092e5a6cdd7..05039e348f07 100644
--- a/kernel/watchdog.c
+++ b/kernel/watchdog.c
@@ -45,11 +45,6 @@ static DEFINE_PER_CPU(unsigned long, soft_lockup_hrtimer_cnt);
static DEFINE_PER_CPU(bool, hard_watchdog_warn);
static DEFINE_PER_CPU(bool, watchdog_nmi_touch);
static DEFINE_PER_CPU(unsigned long, hrtimer_interrupts_saved);
-#endif
-#ifdef CONFIG_HARDLOCKUP_DETECTOR_OTHER_CPU
-static cpumask_t __read_mostly watchdog_cpus;
-#endif
-#ifdef CONFIG_HARDLOCKUP_DETECTOR_NMI
static DEFINE_PER_CPU(struct perf_event *, watchdog_ev);
#endif
@@ -183,7 +178,7 @@ void touch_softlockup_watchdog_sync(void)
__raw_get_cpu_var(watchdog_touch_ts) = 0;
}
-#ifdef CONFIG_HARDLOCKUP_DETECTOR_NMI
+#ifdef CONFIG_HARDLOCKUP_DETECTOR
/* watchdog detector functions */
static int is_hardlockup(void)
{
@@ -197,76 +192,6 @@ static int is_hardlockup(void)
}
#endif
-#ifdef CONFIG_HARDLOCKUP_DETECTOR_OTHER_CPU
-static unsigned int watchdog_next_cpu(unsigned int cpu)
-{
- cpumask_t cpus = watchdog_cpus;
- unsigned int next_cpu;
-
- next_cpu = cpumask_next(cpu, &cpus);
- if (next_cpu >= nr_cpu_ids)
- next_cpu = cpumask_first(&cpus);
-
- if (next_cpu == cpu)
- return nr_cpu_ids;
-
- return next_cpu;
-}
-
-static int is_hardlockup_other_cpu(unsigned int cpu)
-{
- unsigned long hrint = per_cpu(hrtimer_interrupts, cpu);
-
- if (per_cpu(hrtimer_interrupts_saved, cpu) == hrint)
- return 1;
-
- per_cpu(hrtimer_interrupts_saved, cpu) = hrint;
- return 0;
-}
-
-static void watchdog_check_hardlockup_other_cpu(void)
-{
- unsigned int next_cpu;
-
- /*
- * Test for hardlockups every 3 samples. The sample period is
- * watchdog_thresh * 2 / 5, so 3 samples gets us back to slightly over
- * watchdog_thresh (over by 20%).
- */
- if (__this_cpu_read(hrtimer_interrupts) % 3 != 0)
- return;
-
- /* check for a hardlockup on the next cpu */
- next_cpu = watchdog_next_cpu(smp_processor_id());
- if (next_cpu >= nr_cpu_ids)
- return;
-
- smp_rmb();
-
- if (per_cpu(watchdog_nmi_touch, next_cpu) == true) {
- per_cpu(watchdog_nmi_touch, next_cpu) = false;
- return;
- }
-
- if (is_hardlockup_other_cpu(next_cpu)) {
- /* only warn once */
- if (per_cpu(hard_watchdog_warn, next_cpu) == true)
- return;
-
- if (hardlockup_panic)
- panic("Watchdog detected hard LOCKUP on cpu %u", next_cpu);
- else
- WARN(1, "Watchdog detected hard LOCKUP on cpu %u", next_cpu);
-
- per_cpu(hard_watchdog_warn, next_cpu) = true;
- } else {
- per_cpu(hard_watchdog_warn, next_cpu) = false;
- }
-}
-#else
-static inline void watchdog_check_hardlockup_other_cpu(void) { return; }
-#endif
-
static int is_softlockup(unsigned long touch_ts)
{
unsigned long now = get_timestamp();
@@ -278,7 +203,7 @@ static int is_softlockup(unsigned long touch_ts)
return 0;
}
-#ifdef CONFIG_HARDLOCKUP_DETECTOR_NMI
+#ifdef CONFIG_HARDLOCKUP_DETECTOR
static struct perf_event_attr wd_hw_attr = {
.type = PERF_TYPE_HARDWARE,
@@ -326,7 +251,7 @@ static void watchdog_overflow_callback(struct perf_event *event,
__this_cpu_write(hard_watchdog_warn, false);
return;
}
-#endif /* CONFIG_HARDLOCKUP_DETECTOR_NMI */
+#endif /* CONFIG_HARDLOCKUP_DETECTOR */
static void watchdog_interrupt_count(void)
{
@@ -346,9 +271,6 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer)
/* kick the hardlockup detector */
watchdog_interrupt_count();
- /* test for hardlockups on the next cpu */
- watchdog_check_hardlockup_other_cpu();
-
/* kick the softlockup detector */
wake_up_process(__this_cpu_read(softlockup_watchdog));
@@ -473,7 +395,7 @@ static void watchdog(unsigned int cpu)
__touch_watchdog();
}
-#ifdef CONFIG_HARDLOCKUP_DETECTOR_NMI
+#ifdef CONFIG_HARDLOCKUP_DETECTOR
/*
* People like the simple clean cpu node info on boot.
* Reduce the watchdog noise by only printing messages
@@ -549,44 +471,9 @@ static void watchdog_nmi_disable(unsigned int cpu)
return;
}
#else
-#ifdef CONFIG_HARDLOCKUP_DETECTOR_OTHER_CPU
-static int watchdog_nmi_enable(unsigned int cpu)
-{
- /*
- * The new cpu will be marked online before the first hrtimer interrupt
- * runs on it. If another cpu tests for a hardlockup on the new cpu
- * before it has run its first hrtimer, it will get a false positive.
- * Touch the watchdog on the new cpu to delay the first check for at
- * least 3 sampling periods to guarantee one hrtimer has run on the new
- * cpu.
- */
- per_cpu(watchdog_nmi_touch, cpu) = true;
- smp_wmb();
- cpumask_set_cpu(cpu, &watchdog_cpus);
- return 0;
-}
-
-static void watchdog_nmi_disable(unsigned int cpu)
-{
- unsigned int next_cpu = watchdog_next_cpu(cpu);
-
- /*
- * Offlining this cpu will cause the cpu before this one to start
- * checking the one after this one. If this cpu just finished checking
- * the next cpu and updating hrtimer_interrupts_saved, and then the
- * previous cpu checks it within one sample period, it will trigger a
- * false positive. Touch the watchdog on the next cpu to prevent it.
- */
- if (next_cpu < nr_cpu_ids)
- per_cpu(watchdog_nmi_touch, next_cpu) = true;
- smp_wmb();
- cpumask_clear_cpu(cpu, &watchdog_cpus);
-}
-#else
static int watchdog_nmi_enable(unsigned int cpu) { return 0; }
static void watchdog_nmi_disable(unsigned int cpu) { return; }
-#endif /* CONFIG_HARDLOCKUP_DETECTOR_OTHER_CPU */
-#endif /* CONFIG_HARDLOCKUP_DETECTOR_NMI */
+#endif /* CONFIG_HARDLOCKUP_DETECTOR */
/* prepare/enable/disable routines */
/* sysctl functions */
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index d317c1ad62ab..66bde7034df8 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -191,27 +191,15 @@ config LOCKUP_DETECTOR
The overhead should be minimal. A periodic hrtimer runs to
generate interrupts and kick the watchdog task every 4 seconds.
An NMI is generated every 10 seconds or so to check for hardlockups.
- If NMIs are not available on the platform, every 12 seconds the
- hrtimer interrupt on one cpu will be used to check for hardlockups
- on the next cpu.
The frequency of hrtimer and NMI events and the soft and hard lockup
thresholds can be controlled through the sysctl watchdog_thresh.
-config HARDLOCKUP_DETECTOR_NMI
+config HARDLOCKUP_DETECTOR
def_bool y
depends on LOCKUP_DETECTOR && !HAVE_NMI_WATCHDOG
depends on PERF_EVENTS && HAVE_PERF_EVENTS_NMI
-config HARDLOCKUP_DETECTOR_OTHER_CPU
- def_bool y
- depends on LOCKUP_DETECTOR && SMP
- depends on !HARDLOCKUP_DETECTOR_NMI && !HAVE_NMI_WATCHDOG
-
-config HARDLOCKUP_DETECTOR
- def_bool y
- depends on HARDLOCKUP_DETECTOR_NMI || HARDLOCKUP_DETECTOR_OTHER_CPU
-
config BOOTPARAM_HARDLOCKUP_PANIC
bool "Panic (Reboot) On Hard Lockups"
depends on HARDLOCKUP_DETECTOR
diff --git a/linaro/configs/android.conf b/linaro/configs/android.conf
index 538adefff80f..86ebfe2a380b 100644
--- a/linaro/configs/android.conf
+++ b/linaro/configs/android.conf
@@ -1,5 +1,6 @@
CONFIG_IPV6=y
# CONFIG_IPV6_SIT is not set
+# CONFIG_INITRAMFS_SOURCE is not set
CONFIG_PANIC_TIMEOUT=0
CONFIG_HAS_WAKELOCK=y
CONFIG_WAKELOCK=y