aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrey Konovalov <andrey.konovalov@linaro.org>2013-10-17 18:24:00 +0400
committerAndrey Konovalov <andrey.konovalov@linaro.org>2013-10-17 18:24:00 +0400
commit804a2fa7ddc7a2b4b2dac7fa2d569e0bff5aad12 (patch)
treeaacbb4bc5e06153f27d1f2c6e9b17f9392b05fb3
parent57c6042028e0b4c8911038124adc1e6f4abe8112 (diff)
parentbd6757f02ea091ecf15bc188672d93b04ca16250 (diff)
Merge branch 'tracking-integration-hilt-linux-linaro' into merge-linux-linaroll-20131017.0ll_20131017.0
-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/mmc/k3-dw-mshc.txt66
-rw-r--r--arch/arm/Kconfig2
-rw-r--r--arch/arm/Makefile1
-rw-r--r--arch/arm/boot/dts/Makefile2
-rw-r--r--arch/arm/boot/dts/hi3620.dtsi1599
-rw-r--r--arch/arm/boot/dts/hi3716-dkb.dts56
-rw-r--r--arch/arm/boot/dts/hi3716.dtsi256
-rw-r--r--arch/arm/boot/dts/hi4511.dts1477
-rw-r--r--arch/arm/configs/multi_v7_defconfig1
-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.c64
-rw-r--r--drivers/clk/Kconfig1
-rw-r--r--drivers/clk/Makefile1
-rw-r--r--drivers/clk/hisilicon/Kconfig3
-rw-r--r--drivers/clk/hisilicon/Makefile1
-rw-r--r--drivers/clk/hisilicon/clk-hi3716.c268
-rw-r--r--drivers/clk/hisilicon/clk-hi3xxx.c656
-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/Kconfig8
-rw-r--r--drivers/mfd/Makefile1
-rw-r--r--drivers/mfd/hi6421-pmic-core.c302
-rw-r--r--drivers/mmc/host/Kconfig10
-rw-r--r--drivers/mmc/host/Makefile1
-rw-r--r--drivers/mmc/host/dw_mmc-k3.c392
-rw-r--r--drivers/mmc/host/dw_mmc.c2
-rw-r--r--drivers/regulator/Kconfig7
-rw-r--r--drivers/regulator/Makefile2
-rw-r--r--drivers/regulator/hi6421-regulator.c556
-rw-r--r--drivers/rtc/rtc-pl031.c27
-rw-r--r--include/linux/mfd/hi6421-pmic.h99
-rw-r--r--include/linux/mmc/dw_mmc.h2
44 files changed, 9686 insertions, 3 deletions
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/mmc/k3-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/k3-dw-mshc.txt
new file mode 100644
index 000000000000..54a9d8bfdfaf
--- /dev/null
+++ b/Documentation/devicetree/bindings/mmc/k3-dw-mshc.txt
@@ -0,0 +1,66 @@
+* 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.
+* vmmc-supply: should be vmmc used in dwmmc
+* fifo-depth: should be provided if register can not provide correct value
+* clken-reg: should be clock enable register and offset
+* drv-sel-reg: should be driver delay select register and offset
+* sam-sel-reg: should be sample delay select register and offset
+* div-reg: should be divider register and offset
+
+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";
+ clken-reg = <0x1f8 0>;
+ drv-sel-reg = <0x1f8 4>;
+ sam-sel-reg = <0x1f8 8>;
+ div-reg = <0x1f8 1>;
+ };
+ 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>;
+ };
+ };
+
+PCTRL:
+
+Required Properties:
+* compatible: should be
+ - "hisilicon,pctrl": Peripheral control
+
+Example:
+
+ pctrl: pctrl@fca09000 {
+ compatible = "hisilicon,pctrl";
+ reg = <0xfca09000 0x1000>;
+ };
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 46fcf5f7f7bd..b2d1acc62247 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -954,6 +954,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/Makefile b/arch/arm/Makefile
index 1b1e3c9138d0..f4ba7b29ca2b 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -157,6 +157,7 @@ machine-$(CONFIG_ARCH_EP93XX) += ep93xx
machine-$(CONFIG_ARCH_EXYNOS) += exynos
machine-$(CONFIG_ARCH_GEMINI) += gemini
machine-$(CONFIG_ARCH_HIGHBANK) += highbank
+machine-$(CONFIG_ARCH_HI3xxx) += 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 a3178d1d435d..09450c686bae 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -68,6 +68,8 @@ dtb-$(CONFIG_ARCH_EXYNOS) += exynos4210-origen.dtb \
exynos5440-ssdk5440.dtb
dtb-$(CONFIG_ARCH_HIGHBANK) += highbank.dtb \
ecx-2000.dtb
+dtb-$(CONFIG_ARCH_HI3xxx) += 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..9829c9cca12e
--- /dev/null
+++ b/arch/arm/boot/dts/hi3620.dtsi
@@ -0,0 +1,1599 @@
+/*
+ * 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 0x80>;
+ };
+ 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 0x100>;
+ };
+ 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 0x200>;
+ };
+ 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 0x400>;
+ };
+ 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 0x800>;
+ };
+
+ 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 0x4>;
+ };
+
+ 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 0x1000>;
+ };
+ 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 0x2000>;
+ };
+ 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 0x4000>;
+ };
+ 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 0x8000>;
+ };
+ 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 0x20000>;
+ };
+ 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 0x80000>;
+ };
+ 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 0x200000>;
+ };
+ 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 0x1>;
+ };
+ 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 0x4>;
+ };
+ 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 0x10>;
+ };
+ 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 0x40>;
+ };
+ 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 0x8000>;
+ };
+ 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 0x200>;
+ };
+ 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 0x10>;
+ };
+ 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 0x200>;
+ };
+ 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 0x10>;
+ };
+ 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 0x400>;
+ };
+ 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 0x800>;
+ };
+ 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 0x20>;
+ };
+ 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 0x20>;
+ };
+ 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 0x800>;
+ };
+ refclk_ldi0: refclk@32 {
+ compatible = "hisilicon,hi3620-clk-mux";
+ #clock-cells = <0>;
+ hiword;
+ clocks = <&pll_peri &pll_usb &pll_hdmi>;
+ clock-output-names = "rclk_ldi0";
+ hisilicon,clkmux-reg = <0x114 0x6000>;
+ hisilicon,clkmux-table = <0 0x6000>;
+ };
+ refclk_ldi1: refclk@33 {
+ compatible = "hisilicon,hi3620-clk-mux";
+ #clock-cells = <0>;
+ hiword;
+ clocks = <&pll_peri &pll_usb &pll_hdmi>;
+ clock-output-names = "rclk_ldi1";
+ hisilicon,clkmux-reg = <0x118 0xc000>;
+ hisilicon,clkmux-table = <0 0xc000>;
+ };
+ 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 0x400>;
+ };
+ 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 0x800>;
+ };
+ 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";
+ 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";
+ 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";
+ 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";
+ 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";
+ 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";
+ 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";
+ 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";
+ 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";
+ 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";
+ 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";
+ 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";
+ 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";
+ 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";
+ 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";
+ 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";
+ 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";
+ 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";
+ 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";
+ 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";
+ 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";
+ 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";
+ 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";
+ clken-reg = <0x1f8 12>;
+ drv-sel-reg = <0x1f8 16>;
+ sam-sel-reg = <0x1f8 20>;
+ div-reg = <0x1f8 13>;
+ };
+
+ /* 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";
+ clken-reg = <0x1f8 0>;
+ drv-sel-reg = <0x1f8 4>;
+ sam-sel-reg = <0x1f8 8>;
+ div-reg = <0x1f8 1>;
+ };
+
+ dwmmc_2: dwmmc2@fcd05000 {
+ compatible = "hisilicon,hi4511-dw-mshc";
+ reg = <0xfcd05000 0x1000>;
+ interrupts = <0 18 4>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clocks = <&mmcclk2>;
+ clken-reg = <0x1f8 24>;
+ drv-sel-reg = <0x1f8 28>;
+ sam-sel-reg = <0x1fc 0>;
+ div-reg = <0x1f8 25>;
+ };
+
+ dwmmc_3: dwmmc3@fcd06000 {
+ compatible = "hisilicon,hi4511-dw-mshc";
+ reg = <0xfcd06000 0x1000>;
+ interrupts = <0 19 4>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clocks = <&mmcclk3>;
+ clken-reg = <0x1fc 4>;
+ drv-sel-reg = <0x1fc 8>;
+ sam-sel-reg = <0x1fc 12>;
+ div-reg = <0x1f8 5>;
+ };
+
+ 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..91beec5f236f
--- /dev/null
+++ b/arch/arm/boot/dts/hi3716-dkb.dts
@@ -0,0 +1,56 @@
+/*
+ * 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";
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/hi3716.dtsi b/arch/arm/boot/dts/hi3716.dtsi
new file mode 100644
index 000000000000..5eea43c055f5
--- /dev/null
+++ b/arch/arm/boot/dts/hi3716.dtsi
@@ -0,0 +1,256 @@
+/*
+ * 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";
+ };
+ };
+
+ 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";
+ };
+ };
+
+ 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..c16690fd50c7
--- /dev/null
+++ b/arch/arm/boot/dts/hi4511.dts
@@ -0,0 +1,1477 @@
+/*
+ * 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 mem=512m 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 {
+ reg = <0x00000000 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/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig
index 4a5903e04827..c0fadd76fff8 100644
--- a/arch/arm/configs/multi_v7_defconfig
+++ b/arch/arm/configs/multi_v7_defconfig
@@ -22,6 +22,7 @@ CONFIG_SOC_OMAP5=y
CONFIG_SOC_AM33XX=y
CONFIG_SOC_AM43XX=y
CONFIG_ARCH_ROCKCHIP=y
+CONFIG_ARCH_HI3xxx=y
CONFIG_ARCH_SOCFPGA=y
CONFIG_PLAT_SPEAR=y
CONFIG_ARCH_SPEAR13XX=y
diff --git a/arch/arm/mach-hs/Kconfig b/arch/arm/mach-hs/Kconfig
new file mode 100644
index 000000000000..6b1e18c57118
--- /dev/null
+++ b/arch/arm/mach-hs/Kconfig
@@ -0,0 +1,21 @@
+config ARCH_HI3xxx
+ 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_HI3xxx
+
+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..ec2388b88612
--- /dev/null
+++ b/arch/arm/mach-hs/core.h
@@ -0,0 +1,28 @@
+#ifndef __HISILICON_CORE_H
+#define __HISILICON_CORE_H
+
+#include <linux/reboot.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(enum reboot_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..64cfe34cef89
--- /dev/null
+++ b/arch/arm/mach-hs/system.c
@@ -0,0 +1,64 @@
+/*
+ * 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(enum reboot_mode mode, const char *cmd)
+{
+ writel_relaxed(0xdeadbeef, hs_sctrl_base + hs_reboot_reg);
+
+ while (1)
+ cpu_do_idle();
+}
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 279407a36391..b16766c5baad 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -95,4 +95,5 @@ config CLK_PPC_CORENET
endmenu
+source "drivers/clk/hisilicon/Kconfig"
source "drivers/clk/mvebu/Kconfig"
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 7b111062ccba..04994da8742a 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o
obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o
obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o
obj-$(CONFIG_ARCH_NSPIRE) += clk-nspire.o
+obj-$(CONFIG_ARCH_HI3xxx) += hisilicon/
obj-$(CONFIG_ARCH_MXS) += mxs/
obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/
obj-$(CONFIG_PLAT_SPEAR) += spear/
diff --git a/drivers/clk/hisilicon/Kconfig b/drivers/clk/hisilicon/Kconfig
new file mode 100644
index 000000000000..344ddb764c1f
--- /dev/null
+++ b/drivers/clk/hisilicon/Kconfig
@@ -0,0 +1,3 @@
+config HI3xxx_CLK_CORE
+ bool "Core clock driver of Hi3xxx Soc"
+ default y if COMMON_CLK
diff --git a/drivers/clk/hisilicon/Makefile b/drivers/clk/hisilicon/Makefile
new file mode 100644
index 000000000000..682b8dc12b04
--- /dev/null
+++ b/drivers/clk/hisilicon/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_HI3xxx_CLK_CORE) += clk-hi3xxx.o clk-hi3716.o
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..68691c12fdf8
--- /dev/null
+++ b/drivers/clk/hisilicon/clk-hi3xxx.c
@@ -0,0 +1,656 @@
+/*
+ * 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 int __init hi3xxx_parse_mux(struct device_node *np,
+ u8 *num_parents,
+ u32 *table)
+{
+ int i, cnt, ret;
+
+ /* get the count of items in mux */
+ for (i = 0, cnt = 0; ; i++, cnt++) {
+ /* parent's #clock-cells property is always 0 */
+ if (!of_parse_phandle(np, "clocks", i))
+ break;
+ }
+
+ for (i = 0; i < cnt; i++) {
+ if (!of_clk_get_parent_name(np, i))
+ return -ENOENT;
+ }
+ *num_parents = cnt;
+ table = kzalloc(sizeof(u32 *) * cnt, GFP_KERNEL);
+ if (!table)
+ return -ENOMEM;
+ ret = of_property_read_u32_array(np, "hisilicon,clkmux-table",
+ table, cnt);
+ if (ret)
+ goto err;
+ return 0;
+err:
+ kfree(table);
+ return ret;
+}
+
+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 num_parents, shift, flag = 0;
+ void __iomem *reg, *base;
+ int i, 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;
+
+ ret = hi3xxx_parse_mux(np, &num_parents, table);
+ if (ret)
+ return;
+
+ parent_names = kzalloc(sizeof(char *) * num_parents, GFP_KERNEL);
+ if (!parent_names)
+ goto err;
+ for (i = 0; i < num_parents; 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, num_parents,
+ 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;
+ /* 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,
+ 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_warn("%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;
+
+ 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;
+
+ 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/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index e09ec67957a3..6be3908a43a4 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -919,4 +919,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 f5216c1bf53e..967014672ae6 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -75,3 +75,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 89d9d44683ab..dec56df228e1 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -1151,6 +1151,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 409fb6260926..d60a7cab76c9 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -163,3 +163,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..b2d7c4e82bd2
--- /dev/null
+++ b/drivers/mfd/hi6421-pmic-core.c
@@ -0,0 +1,302 @@
+/*
+ * 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_create_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 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;
+
+ 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/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 7e89650fb31e..f3723357a64f 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -575,6 +575,16 @@ config MMC_DW_SOCFPGA
This selects support for Altera SoCFPGA specific extensions to the
Synopsys DesignWare Memory Card Interface driver.
+config MMC_DW_K3
+ tristate "K3 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 Hisilicon K3 SoC specific extensions to the
+ Synopsys DesignWare Memory Card Interface driver. Select this option
+ for platforms based on Hisilicon K3 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 c41d0c364509..64f5f8d35839 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -43,6 +43,7 @@ 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_SOCFPGA) += dw_mmc-socfpga.o
+obj-$(CONFIG_MMC_DW_K3) += dw_mmc-k3.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-k3.c b/drivers/mmc/host/dw_mmc-k3.c
new file mode 100644
index 000000000000..f46453fe0c57
--- /dev/null
+++ b/drivers/mmc/host/dw_mmc-k3.c
@@ -0,0 +1,392 @@
+/*
+ * 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/of_address.h>
+
+#include "dw_mmc.h"
+#include "dw_mmc-pltfm.h"
+
+#define DRIVER_NAME "dwmmc_k3"
+
+enum dw_mci_k3_type {
+ DW_MCI_TYPE_HI4511,
+};
+
+static struct dw_mci_k3_compatible {
+ char *compatible;
+ enum dw_mci_k3_type type;
+} k3_compat[] = {
+ {
+ .compatible = "hisilicon,hi4511-dw-mshc",
+ .type = DW_MCI_TYPE_HI4511,
+ },
+};
+
+struct dw_mci_k3_priv_data {
+ enum dw_mci_k3_type type;
+ int old_timing;
+ u32 id;
+ u32 gpio_cd;
+ u32 clken_reg;
+ u32 clken_bit;
+ u32 sam_sel_reg;
+ u32 sam_sel_bit;
+ u32 drv_sel_reg;
+ u32 drv_sel_bit;
+ u32 div_reg;
+ u32 div_bit;
+};
+
+static void __iomem *pctrl;
+static DEFINE_SPINLOCK(mmc_tuning_lock);
+static int k3_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_k3_set_timing(struct dw_mci_k3_priv_data *priv,
+ int idx, int sam, int drv, int div)
+{
+ unsigned int clken_reg = priv->clken_reg;
+ unsigned int clken_bit = priv->clken_bit;
+ unsigned int sam_sel_reg = priv->sam_sel_reg;
+ unsigned int sam_sel_bit = priv->sam_sel_bit;
+ unsigned int drv_sel_reg = priv->drv_sel_reg;
+ unsigned int drv_sel_bit = priv->drv_sel_bit;
+ unsigned int div_reg = priv->div_reg;
+ unsigned int div_bit = priv->div_bit;
+ int i = 0;
+ unsigned int temp_reg;
+ unsigned long flags;
+
+ 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 + div_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 + div_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_k3_tun(struct dw_mci *host, int id, int index)
+{
+ struct dw_mci_k3_priv_data *priv = host->priv;
+ int ret;
+
+ if (!pctrl)
+ return;
+
+ if (priv->old_timing == index)
+ return;
+
+ ret = clk_set_rate(host->ciu_clk, k3_tuning_config[id][index][0]);
+ if (ret)
+ dev_err(host->dev, "clk_set_rate failed\n");
+
+ dw_mci_k3_set_timing(priv, id,
+ (k3_tuning_config[id][index][3] +
+ k3_tuning_config[id][index][4]) / 2,
+ k3_tuning_config[id][index][2],
+ k3_tuning_config[id][index][1]);
+
+ host->bus_hz = k3_tuning_config[id][index][5];
+ priv->old_timing = index;
+}
+
+static void dw_mci_k3_set_ios(struct dw_mci *host, struct mmc_ios *ios)
+{
+ struct dw_mci_k3_priv_data *priv = host->priv;
+ int id = priv->id;
+
+ if (priv->type == DW_MCI_TYPE_HI4511)
+ dw_mci_k3_tun(host, id, ios->timing);
+}
+
+static int dw_mci_k3_priv_init(struct dw_mci *host)
+{
+ struct dw_mci_k3_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(k3_compat); i++) {
+ if (of_device_is_compatible(host->dev->of_node,
+ k3_compat[i].compatible))
+ priv->type = k3_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_k3_setup_clock(struct dw_mci *host)
+{
+ struct dw_mci_k3_priv_data *priv = host->priv;
+
+ if (priv->type == DW_MCI_TYPE_HI4511)
+ dw_mci_k3_tun(host, priv->id, MMC_TIMING_LEGACY);
+
+ return 0;
+}
+
+
+static irqreturn_t dw_mci_k3_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_k3_get_cd(struct dw_mci *host, u32 slot_id)
+{
+ unsigned int status;
+ struct dw_mci_k3_priv_data *priv = host->priv;
+
+ status = !gpio_get_value(priv->gpio_cd);
+ return status;
+}
+
+static int dw_mci_k3_parse_dt(struct dw_mci *host)
+{
+ struct dw_mci_k3_priv_data *priv = host->priv;
+ struct device_node *np = host->dev->of_node;
+ u32 data[2];
+ int ret;
+
+ if (priv->type == DW_MCI_TYPE_HI4511) {
+ ret = of_property_read_u32_array(np,
+ "clken-reg", data, 2);
+ if (!ret) {
+ priv->clken_reg = data[0];
+ priv->clken_bit = data[1];
+ }
+
+ ret = of_property_read_u32_array(np,
+ "drv-sel-reg", data, 2);
+ if (!ret) {
+ priv->drv_sel_reg = data[0];
+ priv->drv_sel_bit = data[1];
+ }
+
+ ret = of_property_read_u32_array(np,
+ "sam-sel-reg", data, 2);
+ if (!ret) {
+ priv->sam_sel_reg = data[0];
+ priv->sam_sel_bit = data[1];
+ }
+
+ ret = of_property_read_u32_array(np,
+ "div-reg", data, 2);
+ if (!ret) {
+ priv->div_reg = data[0];
+ priv->div_bit = data[1];
+ }
+ }
+
+ return 0;
+}
+
+static unsigned long k3_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 k3_drv_data = {
+ .caps = k3_dwmmc_caps,
+ .init = dw_mci_k3_priv_init,
+ .set_ios = dw_mci_k3_set_ios,
+ .setup_clock = dw_mci_k3_setup_clock,
+ .parse_dt = dw_mci_k3_parse_dt,
+};
+
+static const struct of_device_id dw_mci_k3_match[] = {
+ { .compatible = "hisilicon,hi4511-dw-mshc",
+ .data = &k3_drv_data, },
+ {},
+};
+MODULE_DEVICE_TABLE(of, dw_mci_k3_match);
+
+int dw_mci_k3_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_k3_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_k3_priv_data *priv = host->priv;
+ priv->gpio_cd = gpio;
+ host->pdata->get_cd = dw_mci_k3_get_cd;
+ err = devm_request_irq(host->dev, gpio_to_irq(gpio),
+ dw_mci_k3_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_k3_suspend(struct device *dev)
+{
+ int ret;
+ struct dw_mci *host = dev_get_drvdata(dev);
+
+ ret = dw_mci_suspend(host);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int dw_mci_k3_resume(struct device *dev)
+{
+ int ret;
+ struct dw_mci *host = dev_get_drvdata(dev);
+ struct dw_mci_k3_priv_data *priv = host->priv;
+
+ if (priv->type == DW_MCI_TYPE_HI4511) {
+ int id = priv->id;
+
+ priv->old_timing = -1;
+ dw_mci_k3_tun(host, id, MMC_TIMING_LEGACY);
+ }
+
+ ret = dw_mci_resume(host);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+SIMPLE_DEV_PM_OPS(dw_mci_k3_pmops, dw_mci_k3_suspend, dw_mci_k3_resume);
+
+static struct platform_driver dw_mci_k3_pltfm_driver = {
+ .probe = dw_mci_k3_probe,
+ .remove = dw_mci_pltfm_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ .of_match_table = dw_mci_k3_match,
+ .pm = &dw_mci_k3_pmops,
+ },
+};
+
+module_platform_driver(dw_mci_k3_pltfm_driver);
+
+MODULE_DESCRIPTION("K3 Specific DW-MSHC Driver Extension");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index d73b52daef71..e49f16e88e99 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -877,7 +877,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;
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index dfe58096b374..af7086c9ba08 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -571,5 +571,12 @@ config REGULATOR_WM8994
This driver provides support for the voltage regulators on the
WM8994 CODEC.
+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 185cce246022..556ab2946eb9 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -76,6 +76,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..9ffef468faaa
--- /dev/null
+++ b/drivers/regulator/hi6421-regulator.c
@@ -0,0 +1,556 @@
+/*
+ * 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;
+
+ /* 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);
+
+ 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/rtc-pl031.c b/drivers/rtc/rtc-pl031.c
index e3b25712b659..7fbb5c1d38fc 100644
--- a/drivers/rtc/rtc-pl031.c
+++ b/drivers/rtc/rtc-pl031.c
@@ -401,6 +401,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 = {
@@ -470,6 +496,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/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/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
index 198f0fa44e9f..5a359dc44705 100644
--- a/include/linux/mmc/dw_mmc.h
+++ b/include/linux/mmc/dw_mmc.h
@@ -246,7 +246,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);
/*