the support is still WIP. next steps are to make the pmic and ethernet work.
this is the first commit to make sure nothing gets lost.
Signed-off-by: John Crispin <blogic@openwrt.org>
SVN-Revision: 47354
--- /dev/null
+# Copyright (c) 2015 OpenWrt.org
+#
+include $(TOPDIR)/rules.mk
+
+ARCH:=arm
+BOARD:=mediatek
+BOARDNAME:=Mediatek Ralink ARM
+FEATURES:=squashfs
+CPU_TYPE:=cortex-a7
+MAINTAINER:=John Crispin <blogic@openwrt.org>
+
+KERNEL_PATCHVER:=4.1
+
+KERNELNAME:=Image dtbs zImage
+
+include $(INCLUDE_DIR)/target.mk
+DEFAULT_PACKAGES += \
+ kmod-leds-gpio kmod-gpio-button-hotplug swconfig
+
+$(eval $(call BuildTarget))
--- /dev/null
+define Package/base-files/install-target
+ rm -f $(1)/etc/config/network
+endef
--- /dev/null
+::sysinit:/etc/init.d/rcS S boot
+::shutdown:/etc/init.d/rcS K shutdown
+ttyS0::askfirst:/bin/ash --login
--- /dev/null
+#!/bin/sh
+#
+# Copyright (C) 2015 OpenWrt.org
+#
+
+mediatek_board_detect() {
+ local machine
+ local name
+
+ machine=$(cat /proc/device-tree/model)
+
+ case "$machine" in
+ "MediaTek MT7623 Evaluation Board")
+ name="mt7623_evb"
+ ;;
+ esac
+
+ [ -z "$name" ] && name="unknown"
+
+ [ -e "/tmp/sysinfo/" ] || mkdir -p "/tmp/sysinfo/"
+
+ echo "$name" > /tmp/sysinfo/board_name
+ echo "$machine" > /tmp/sysinfo/model
+}
+
+mediatek_board_name() {
+ local name
+
+ [ -f /tmp/sysinfo/board_name ] && name=$(cat /tmp/sysinfo/board_name)
+ [ -z "$name" ] && name="unknown"
+
+ echo "$name"
+}
--- /dev/null
+#!/bin/sh
+#
+# Copyright (c) 2014 The Linux Foundation. All rights reserved.
+#
+
+do_mediatek() {
+ . /lib/mediatek.sh
+
+ mediatek_board_detect
+}
+
+boot_hook_add preinit_main do_mediatek
--- /dev/null
+# CONFIG_AIO is not set
+CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_APM_EMULATION is not set
+# CONFIG_ARCH_ALPINE is not set
+CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
+CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
+CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y
+CONFIG_ARCH_HAS_SG_CHAIN=y
+CONFIG_ARCH_HAS_TICK_BROADCAST=y
+CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_MEDIATEK=y
+CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
+CONFIG_ARCH_MT7623=y
+CONFIG_ARCH_MULTIPLATFORM=y
+# CONFIG_ARCH_MULTI_CPU_AUTO is not set
+CONFIG_ARCH_MULTI_V6_V7=y
+CONFIG_ARCH_MULTI_V7=y
+CONFIG_ARCH_NR_GPIO=0
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y
+CONFIG_ARCH_SUPPORTS_UPROBES=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_ARCH_USE_BUILTIN_BSWAP=y
+CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
+CONFIG_ARCH_WANT_GENERAL_HUGETLB=y
+CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+CONFIG_ARM=y
+CONFIG_ARM_APPENDED_DTB=y
+CONFIG_ARM_ARCH_TIMER=y
+CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
+# CONFIG_ARM_ATAG_DTB_COMPAT is not set
+CONFIG_ARM_CPU_SUSPEND=y
+# CONFIG_ARM_CPU_TOPOLOGY is not set
+# CONFIG_ARM_CRYPTO is not set
+CONFIG_ARM_GIC=y
+CONFIG_ARM_HAS_SG_CHAIN=y
+CONFIG_ARM_L1_CACHE_SHIFT=6
+CONFIG_ARM_L1_CACHE_SHIFT_6=y
+# CONFIG_ARM_LPAE is not set
+CONFIG_ARM_PATCH_PHYS_VIRT=y
+# CONFIG_ARM_SMMU is not set
+CONFIG_ARM_THUMB=y
+CONFIG_ARM_THUMBEE=y
+CONFIG_ARM_UNWIND=y
+CONFIG_ARM_VIRT_EXT=y
+CONFIG_AUTO_ZRELADDR=y
+CONFIG_AVERAGE=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_BOUNCE=y
+# CONFIG_CACHE_L2X0 is not set
+CONFIG_CLEANCACHE=y
+CONFIG_CLKDEV_LOOKUP=y
+CONFIG_CLKSRC_MMIO=y
+CONFIG_CLKSRC_OF=y
+CONFIG_CLONE_BACKWARDS=y
+CONFIG_CMDLINE="earlyprintk console=ttyS0,115200"
+CONFIG_COMMON_CLK=y
+CONFIG_COMPACTION=y
+CONFIG_COREDUMP=y
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+CONFIG_CPU_HAS_ASID=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+CONFIG_CPU_PABRT_V7=y
+CONFIG_CPU_PM=y
+CONFIG_CPU_RMAP=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_V7=y
+CONFIG_CRC16=y
+# CONFIG_CRC32_SARWATE is not set
+CONFIG_CRC32_SLICEBY8=y
+CONFIG_CROSS_MEMORY_ATTACH=y
+CONFIG_CRYPTO_HW=y
+CONFIG_CRYPTO_XZ=y
+CONFIG_DCACHE_WORD_ACCESS=y
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_LL=y
+CONFIG_DEBUG_LL_INCLUDE="debug/8250.S"
+# CONFIG_DEBUG_MT6589_UART0 is not set
+CONFIG_DEBUG_MT8127_UART0=y
+# CONFIG_DEBUG_MT8135_UART3 is not set
+CONFIG_DEBUG_PREEMPT=y
+CONFIG_DEBUG_UART_8250=y
+# CONFIG_DEBUG_UART_8250_FLOW_CONTROL is not set
+CONFIG_DEBUG_UART_8250_SHIFT=2
+# CONFIG_DEBUG_UART_8250_WORD is not set
+CONFIG_DEBUG_UART_PHYS=0x11004000
+CONFIG_DEBUG_UART_VIRT=0xf1004000
+CONFIG_DEBUG_UNCOMPRESS=y
+# CONFIG_DEBUG_USER is not set
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_DEVMEM=y
+CONFIG_DMADEVICES=y
+CONFIG_DMA_ENGINE=y
+CONFIG_DMA_OF=y
+CONFIG_DTC=y
+# CONFIG_DW_DMAC_PCI is not set
+CONFIG_EARLY_PRINTK=y
+CONFIG_ELF_CORE=y
+CONFIG_ESW_DOUBLE_VLAN_TAG=y
+CONFIG_FREEZER=y
+CONFIG_GE1_RGMII_AN=y
+# CONFIG_GE1_RGMII_FORCE_1000 is not set
+# CONFIG_GE1_RGMII_NONE is not set
+# CONFIG_GE1_TRGMII_FORCE_2000 is not set
+# CONFIG_GE1_TRGMII_FORCE_2600 is not set
+CONFIG_GE2_INTERNAL_GPHY=y
+# CONFIG_GE2_MII_AN is not set
+# CONFIG_GE2_MII_FORCE_100 is not set
+# CONFIG_GE2_RGMII_AN is not set
+# CONFIG_GE2_RGMII_FORCE_1000 is not set
+# CONFIG_GE2_RVMII_FORCE_100 is not set
+CONFIG_GENERIC_ALLOCATOR=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
+CONFIG_GENERIC_IDLE_POLL_SETUP=y
+CONFIG_GENERIC_IO=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GENERIC_IRQ_SHOW_LEVEL=y
+CONFIG_GENERIC_MSI_IRQ=y
+CONFIG_GENERIC_PCI_IOMAP=y
+CONFIG_GENERIC_PHY=y
+CONFIG_GENERIC_PINCONF=y
+CONFIG_GENERIC_SCHED_CLOCK=y
+CONFIG_GENERIC_SMP_IDLE_THREAD=y
+CONFIG_GENERIC_STRNCPY_FROM_USER=y
+CONFIG_GENERIC_STRNLEN_USER=y
+CONFIG_GE_RGMII_INTERNAL_P0_AN=y
+CONFIG_GIGAPHY=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_DEVRES=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_HANDLE_DOMAIN_IRQ=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_HAS_DMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT_MAP=y
+# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
+CONFIG_HAVE_ARCH_AUDITSYSCALL=y
+CONFIG_HAVE_ARCH_BITREVERSE=y
+CONFIG_HAVE_ARCH_JUMP_LABEL=y
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_HAVE_ARCH_PFN_VALID=y
+CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
+CONFIG_HAVE_BPF_JIT=y
+CONFIG_HAVE_CC_STACKPROTECTOR=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_CLK_PREPARE=y
+CONFIG_HAVE_CONTEXT_TRACKING=y
+CONFIG_HAVE_C_RECORDMCOUNT=y
+CONFIG_HAVE_DEBUG_KMEMLEAK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+CONFIG_HAVE_DMA_ATTRS=y
+CONFIG_HAVE_DMA_CONTIGUOUS=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_HAVE_IDE=y
+CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_LZ4=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_LZO=y
+CONFIG_HAVE_KERNEL_XZ=y
+CONFIG_HAVE_MEMBLOCK=y
+CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
+CONFIG_HAVE_NET_DSA=y
+CONFIG_HAVE_OPROFILE=y
+CONFIG_HAVE_OPTPROBES=y
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_HAVE_PERF_REGS=y
+CONFIG_HAVE_PERF_USER_STACK_DUMP=y
+CONFIG_HAVE_PROC_CPU=y
+CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
+CONFIG_HAVE_SMP=y
+CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
+CONFIG_HAVE_UID16=y
+CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
+CONFIG_HIGHMEM=y
+# CONFIG_HIGHPTE is not set
+CONFIG_HOTPLUG_CPU=y
+# CONFIG_HSU_DMA_PCI is not set
+CONFIG_HWMON=y
+CONFIG_HW_RANDOM=y
+# CONFIG_HW_SFQ is not set
+CONFIG_HZ_FIXED=0
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_MT65XX=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_IOMMU_HELPER=y
+# CONFIG_IOMMU_IO_PGTABLE_LPAE is not set
+CONFIG_IOMMU_SUPPORT=y
+CONFIG_IRQCHIP=y
+CONFIG_IRQ_DOMAIN=y
+CONFIG_IRQ_DOMAIN_HIERARCHY=y
+CONFIG_IRQ_FORCED_THREADING=y
+CONFIG_IRQ_WORK=y
+CONFIG_KALLSYMS=y
+CONFIG_LAN_WAN_SUPPORT=y
+# CONFIG_LEDS_REGULATOR is not set
+CONFIG_LIBFDT=y
+CONFIG_LOCKUP_DETECTOR=y
+CONFIG_LOCK_SPIN_ON_OWNER=y
+# CONFIG_LZ4_COMPRESS is not set
+# CONFIG_LZ4_DECOMPRESS is not set
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+# CONFIG_MACH_MT6589 is not set
+# CONFIG_MACH_MT6592 is not set
+CONFIG_MACH_MT7623=y
+CONFIG_MACH_MT8127=y
+# CONFIG_MACH_MT8135 is not set
+CONFIG_MAC_TO_GIGAPHY_MODE_ADDR=0x1F
+CONFIG_MAC_TO_GIGAPHY_MODE_ADDR2=0
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_MDIO_BITBANG=y
+CONFIG_MDIO_BOARDINFO=y
+CONFIG_MDIO_GPIO=y
+CONFIG_MEDIATEK_WATCHDOG=y
+# CONFIG_MFD_MAX77843 is not set
+# CONFIG_MFD_MT6323 is not set
+CONFIG_MFD_SYSCON=y
+CONFIG_MIGHT_HAVE_CACHE_L2X0=y
+CONFIG_MIGHT_HAVE_PCI=y
+CONFIG_MIGRATION=y
+CONFIG_MMC=y
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_MTK=y
+CONFIG_MMC_SDHCI=y
+# CONFIG_MMC_SDHCI_PCI is not set
+CONFIG_MMC_SDHCI_PLTFM=y
+# CONFIG_MMC_TIFM_SD is not set
+CONFIG_MODULES_USE_ELF_REL=y
+CONFIG_MTD_M25P80=y
+CONFIG_MTD_SPI_NOR=y
+CONFIG_MTK_INFRACFG=y
+CONFIG_MTK_PMIC_WRAP=y
+CONFIG_MTK_SCPSYS=y
+# CONFIG_MTK_SMB_HOOK is not set
+CONFIG_MTK_THERMAL=y
+CONFIG_MTK_TIMER=y
+CONFIG_MULTI_IRQ_HANDLER=y
+CONFIG_MUTEX_SPIN_ON_OWNER=y
+CONFIG_NEED_DMA_MAP_STATE=y
+# CONFIG_NEON is not set
+CONFIG_NET_FLOW_LIMIT=y
+CONFIG_NLS=y
+CONFIG_NO_BOOTMEM=y
+CONFIG_NO_HZ=y
+CONFIG_NO_HZ_COMMON=y
+CONFIG_NO_HZ_IDLE=y
+CONFIG_NR_CPUS=4
+CONFIG_OF=y
+CONFIG_OF_ADDRESS=y
+CONFIG_OF_ADDRESS_PCI=y
+CONFIG_OF_EARLY_FLATTREE=y
+CONFIG_OF_FLATTREE=y
+CONFIG_OF_GPIO=y
+CONFIG_OF_IRQ=y
+CONFIG_OF_MDIO=y
+CONFIG_OF_MTD=y
+CONFIG_OF_NET=y
+CONFIG_OF_PCI=y
+CONFIG_OF_PCI_IRQ=y
+CONFIG_OF_RESERVED_MEM=y
+CONFIG_OLD_SIGACTION=y
+CONFIG_OLD_SIGSUSPEND3=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_PCI=y
+# CONFIG_PCIE_IPROC is not set
+# CONFIG_PCI_DOMAINS_GENERIC is not set
+CONFIG_PCI_MSI=y
+CONFIG_PDMA_NEW=y
+CONFIG_PERF_USE_VMALLOC=y
+CONFIG_PGTABLE_LEVELS=2
+CONFIG_PHYLIB=y
+CONFIG_PINCTRL=y
+# CONFIG_PINCTRL_AMD is not set
+# CONFIG_PINCTRL_MT6397 is not set
+CONFIG_PINCTRL_MT7623=y
+CONFIG_PINCTRL_MT8127=y
+# CONFIG_PINCTRL_MT8135 is not set
+CONFIG_PINCTRL_MTK_COMMON=y
+CONFIG_PM=y
+CONFIG_PM_CLK=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP=y
+CONFIG_PM_SLEEP_SMP=y
+CONFIG_POWER_RESET=y
+# CONFIG_POWER_RESET_BRCMSTB is not set
+# CONFIG_POWER_RESET_GPIO is not set
+# CONFIG_POWER_RESET_GPIO_RESTART is not set
+# CONFIG_POWER_RESET_LTC2952 is not set
+# CONFIG_POWER_RESET_SYSCON is not set
+# CONFIG_POWER_RESET_SYSCON_POWEROFF is not set
+CONFIG_POWER_SUPPLY=y
+CONFIG_PREEMPT=y
+CONFIG_PREEMPT_COUNT=y
+# CONFIG_PREEMPT_NONE is not set
+CONFIG_PREEMPT_RCU=y
+CONFIG_PRINTK_TIME=y
+CONFIG_RAETH=y
+CONFIG_RAETH_CHECKSUM_OFFLOAD=y
+# CONFIG_RAETH_DVT is not set
+CONFIG_RAETH_GMAC2=y
+# CONFIG_RAETH_HW_LRO is not set
+# CONFIG_RAETH_HW_VLAN_TX is not set
+# CONFIG_RAETH_LRO is not set
+# CONFIG_RAETH_NAPI is not set
+CONFIG_RAETH_QDMA=y
+CONFIG_RAETH_QDMATX_QDMARX=y
+CONFIG_RAETH_SCATTER_GATHER_RX_DMA=y
+# CONFIG_RAETH_SKB_RECYCLE_2K is not set
+# CONFIG_RAETH_SPECIAL_TAG is not set
+# CONFIG_RAETH_TSO is not set
+CONFIG_RA_NAT_NONE=y
+# CONFIG_RA_NETWORK_TASKLET_BH is not set
+CONFIG_RA_NETWORK_WORKQUEUE_BH=y
+# CONFIG_RCU_BOOST is not set
+CONFIG_RCU_CPU_STALL_TIMEOUT=21
+# CONFIG_RCU_EXPEDITE_BOOT is not set
+CONFIG_RCU_STALL_COMMON=y
+CONFIG_RD_GZIP=y
+CONFIG_REGMAP=y
+CONFIG_REGMAP_MMIO=y
+CONFIG_REGULATOR=y
+# CONFIG_REGULATOR_DEBUG is not set
+# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
+CONFIG_RESET_CONTROLLER=y
+CONFIG_RFS_ACCEL=y
+CONFIG_RPS=y
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_DRV_ABX80X is not set
+# CONFIG_RTC_DRV_CMOS is not set
+CONFIG_RT_3052_ESW=y
+CONFIG_RWSEM_SPIN_ON_OWNER=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_SCHED_HRTICK=y
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SERIAL_8250_DMA is not set
+CONFIG_SERIAL_8250_MT6577=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+CONFIG_SLUB_CPU_PARTIAL=y
+CONFIG_SMP=y
+# CONFIG_SMP_ON_UP is not set
+CONFIG_SPARSE_IRQ=y
+CONFIG_SPI=y
+CONFIG_SPI_BITBANG=y
+CONFIG_SPI_MASTER=y
+CONFIG_SPI_MT65XX=y
+CONFIG_SPMI=y
+CONFIG_SRCU=y
+CONFIG_STOP_MACHINE=y
+# CONFIG_STRIP_ASM_SYMS is not set
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+CONFIG_SWCONFIG=y
+CONFIG_SWIOTLB=y
+CONFIG_SWP_EMULATE=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_THERMAL=y
+# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set
+CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
+# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set
+# CONFIG_THERMAL_EMULATION is not set
+# CONFIG_THERMAL_GOV_FAIR_SHARE is not set
+CONFIG_THERMAL_GOV_STEP_WISE=y
+# CONFIG_THERMAL_GOV_USER_SPACE is not set
+CONFIG_THERMAL_HWMON=y
+CONFIG_THERMAL_OF=y
+# CONFIG_THUMB2_KERNEL is not set
+CONFIG_TICK_CPU_ACCOUNTING=y
+CONFIG_TIMER_STATS=y
+CONFIG_UEVENT_HELPER_PATH=""
+CONFIG_UID16=y
+CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
+CONFIG_UNINLINE_SPIN_UNLOCK=y
+CONFIG_USB=y
+CONFIG_USB_COMMON=y
+# CONFIG_USB_EHCI_HCD is not set
+CONFIG_USB_MT65XX_USB3_PHY=y
+CONFIG_USB_PHY=y
+CONFIG_USB_SUPPORT=y
+# CONFIG_USB_UHCI_HCD is not set
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_XHCI_MTK=y
+CONFIG_USB_XHCI_PCI=y
+CONFIG_USB_XHCI_PLATFORM=y
+CONFIG_USE_OF=y
+# CONFIG_VDSO is not set
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_VFP=y
+CONFIG_VFPv3=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_WAN_AT_P0=y
+# CONFIG_WAN_AT_P4 is not set
+CONFIG_WATCHDOG_CORE=y
+# CONFIG_XEN is not set
+CONFIG_XPS=y
+CONFIG_XZ_DEC_ARM=y
+CONFIG_XZ_DEC_BCJ=y
+CONFIG_ZBOOT_ROM_BSS=0
+CONFIG_ZBOOT_ROM_TEXT=0
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZONE_DMA_FLAG=0
--- /dev/null
+# Copyright (c) 2014 The Linux Foundation. All rights reserved.
+#
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/image.mk
+
+define Image/BuilduImage
+ cat $(LINUX_DIR)/arch/arm/boot/dts/mt7623-evb.dtb >> $(KDIR)/zImage$(1)
+ $(STAGING_DIR_HOST)/bin/lzma e $(KDIR)/zImage$(1) $(KDIR)/zImage$(1).lzma
+ mkimage -A arm -O linux -T kernel -C lzma -a 0x80008000 -e 0x80008000 -n 'MIPS OpenWrt Linux-$(LINUX_VERSION)' -d $(KDIR)/zImage$(1).lzma $(KDIR)/uImage$(1)
+ $(CP) $(KDIR)/uImage$(1) $(BIN_DIR)/$(IMG_PREFIX)-uImage$(1)
+endef
+
+define Image/BuildKernel
+ $(call Image/BuilduImage)
+ifneq ($(CONFIG_TARGET_ROOTFS_INITRAMFS),)
+ $(call Image/BuilduImage,-initramfs)
+endif
+endef
+
+define Image/Build/squashfs
+ $(call prepare_generic_squashfs,$(KDIR)/root.squashfs)
+endef
+
+define Image/Build
+ $(call Image/Build/$(1),$(1))
+endef
+
+$(eval $(call BuildImage))
--- /dev/null
+From a38e86708141d75c643ffd58865c50a925134e4f Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer@pengutronix.de>
+Date: Thu, 23 Apr 2015 10:35:38 +0200
+Subject: [PATCH 01/76] clk: make strings in parent name arrays const
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The clk functions and structs declare the parent_name arrays as
+'const char **parent_names' which means the parent name strings
+are const, but the array itself is not. Use
+'const char * const * parent_names' instead which also makes
+the array const. This allows us to put the parent_name arrays into
+the __initconst section.
+
+Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
+Reviewed-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
+Tested-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
+Acked-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/clk/clk-composite.c | 2 +-
+ drivers/clk/clk-mux.c | 4 ++--
+ include/linux/clk-provider.h | 8 ++++----
+ 3 files changed, 7 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c
+index 956b7e5..077f4c7 100644
+--- a/drivers/clk/clk-composite.c
++++ b/drivers/clk/clk-composite.c
+@@ -188,7 +188,7 @@ static void clk_composite_disable(struct clk_hw *hw)
+ }
+
+ struct clk *clk_register_composite(struct device *dev, const char *name,
+- const char **parent_names, int num_parents,
++ const char * const *parent_names, int num_parents,
+ struct clk_hw *mux_hw, const struct clk_ops *mux_ops,
+ struct clk_hw *rate_hw, const struct clk_ops *rate_ops,
+ struct clk_hw *gate_hw, const struct clk_ops *gate_ops,
+diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c
+index 69a094c..1fa2a8d 100644
+--- a/drivers/clk/clk-mux.c
++++ b/drivers/clk/clk-mux.c
+@@ -114,7 +114,7 @@ const struct clk_ops clk_mux_ro_ops = {
+ EXPORT_SYMBOL_GPL(clk_mux_ro_ops);
+
+ struct clk *clk_register_mux_table(struct device *dev, const char *name,
+- const char **parent_names, u8 num_parents, unsigned long flags,
++ const char * const *parent_names, u8 num_parents, unsigned long flags,
+ void __iomem *reg, u8 shift, u32 mask,
+ u8 clk_mux_flags, u32 *table, spinlock_t *lock)
+ {
+@@ -166,7 +166,7 @@ struct clk *clk_register_mux_table(struct device *dev, const char *name,
+ EXPORT_SYMBOL_GPL(clk_register_mux_table);
+
+ struct clk *clk_register_mux(struct device *dev, const char *name,
+- const char **parent_names, u8 num_parents, unsigned long flags,
++ const char * const *parent_names, u8 num_parents, unsigned long flags,
+ void __iomem *reg, u8 shift, u8 width,
+ u8 clk_mux_flags, spinlock_t *lock)
+ {
+diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
+index df69531..ec609e5 100644
+--- a/include/linux/clk-provider.h
++++ b/include/linux/clk-provider.h
+@@ -209,7 +209,7 @@ struct clk_ops {
+ struct clk_init_data {
+ const char *name;
+ const struct clk_ops *ops;
+- const char **parent_names;
++ const char * const *parent_names;
+ u8 num_parents;
+ unsigned long flags;
+ };
+@@ -426,12 +426,12 @@ extern const struct clk_ops clk_mux_ops;
+ extern const struct clk_ops clk_mux_ro_ops;
+
+ struct clk *clk_register_mux(struct device *dev, const char *name,
+- const char **parent_names, u8 num_parents, unsigned long flags,
++ const char * const *parent_names, u8 num_parents, unsigned long flags,
+ void __iomem *reg, u8 shift, u8 width,
+ u8 clk_mux_flags, spinlock_t *lock);
+
+ struct clk *clk_register_mux_table(struct device *dev, const char *name,
+- const char **parent_names, u8 num_parents, unsigned long flags,
++ const char * const *parent_names, u8 num_parents, unsigned long flags,
+ void __iomem *reg, u8 shift, u32 mask,
+ u8 clk_mux_flags, u32 *table, spinlock_t *lock);
+
+@@ -518,7 +518,7 @@ struct clk_composite {
+ };
+
+ struct clk *clk_register_composite(struct device *dev, const char *name,
+- const char **parent_names, int num_parents,
++ const char * const *parent_names, int num_parents,
+ struct clk_hw *mux_hw, const struct clk_ops *mux_ops,
+ struct clk_hw *rate_hw, const struct clk_ops *rate_ops,
+ struct clk_hw *gate_hw, const struct clk_ops *gate_ops,
+--
+1.7.10.4
+
--- /dev/null
+From f851b4ea6cae9fd5875036b6d3968375882ce56b Mon Sep 17 00:00:00 2001
+From: James Liao <jamesjj.liao@mediatek.com>
+Date: Thu, 23 Apr 2015 10:35:39 +0200
+Subject: [PATCH 02/76] clk: mediatek: Add initial common clock support for
+ Mediatek SoCs.
+
+This patch adds common clock support for Mediatek SoCs, including plls,
+muxes and clock gates.
+
+Signed-off-by: James Liao <jamesjj.liao@mediatek.com>
+Signed-off-by: Henry Chen <henryc.chen@mediatek.com>
+Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
+---
+ drivers/clk/Makefile | 1 +
+ drivers/clk/mediatek/Makefile | 1 +
+ drivers/clk/mediatek/clk-gate.c | 137 ++++++++++++++++
+ drivers/clk/mediatek/clk-gate.h | 49 ++++++
+ drivers/clk/mediatek/clk-mtk.c | 220 ++++++++++++++++++++++++++
+ drivers/clk/mediatek/clk-mtk.h | 159 +++++++++++++++++++
+ drivers/clk/mediatek/clk-pll.c | 332 +++++++++++++++++++++++++++++++++++++++
+ 7 files changed, 899 insertions(+)
+ create mode 100644 drivers/clk/mediatek/Makefile
+ create mode 100644 drivers/clk/mediatek/clk-gate.c
+ create mode 100644 drivers/clk/mediatek/clk-gate.h
+ create mode 100644 drivers/clk/mediatek/clk-mtk.c
+ create mode 100644 drivers/clk/mediatek/clk-mtk.h
+ create mode 100644 drivers/clk/mediatek/clk-pll.c
+
+diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
+index 3d00c25..d965b3f 100644
+--- a/drivers/clk/Makefile
++++ b/drivers/clk/Makefile
+@@ -51,6 +51,7 @@ obj-$(CONFIG_ARCH_HI3xxx) += hisilicon/
+ obj-$(CONFIG_ARCH_HIP04) += hisilicon/
+ obj-$(CONFIG_ARCH_HIX5HD2) += hisilicon/
+ obj-$(CONFIG_COMMON_CLK_KEYSTONE) += keystone/
++obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/
+ ifeq ($(CONFIG_COMMON_CLK), y)
+ obj-$(CONFIG_ARCH_MMP) += mmp/
+ endif
+diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile
+new file mode 100644
+index 0000000..c384e97
+--- /dev/null
++++ b/drivers/clk/mediatek/Makefile
+@@ -0,0 +1 @@
++obj-y += clk-mtk.o clk-pll.o clk-gate.o
+diff --git a/drivers/clk/mediatek/clk-gate.c b/drivers/clk/mediatek/clk-gate.c
+new file mode 100644
+index 0000000..9d77ee3
+--- /dev/null
++++ b/drivers/clk/mediatek/clk-gate.c
+@@ -0,0 +1,137 @@
++/*
++ * Copyright (c) 2014 MediaTek Inc.
++ * Author: James Liao <jamesjj.liao@mediatek.com>
++ *
++ * 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.
++ */
++
++#include <linux/of.h>
++#include <linux/of_address.h>
++
++#include <linux/io.h>
++#include <linux/slab.h>
++#include <linux/delay.h>
++#include <linux/clkdev.h>
++
++#include "clk-mtk.h"
++#include "clk-gate.h"
++
++static int mtk_cg_bit_is_cleared(struct clk_hw *hw)
++{
++ struct mtk_clk_gate *cg = to_clk_gate(hw);
++ u32 val;
++
++ regmap_read(cg->regmap, cg->sta_ofs, &val);
++
++ val &= BIT(cg->bit);
++
++ return val == 0;
++}
++
++static int mtk_cg_bit_is_set(struct clk_hw *hw)
++{
++ struct mtk_clk_gate *cg = to_clk_gate(hw);
++ u32 val;
++
++ regmap_read(cg->regmap, cg->sta_ofs, &val);
++
++ val &= BIT(cg->bit);
++
++ return val != 0;
++}
++
++static void mtk_cg_set_bit(struct clk_hw *hw)
++{
++ struct mtk_clk_gate *cg = to_clk_gate(hw);
++
++ regmap_write(cg->regmap, cg->set_ofs, BIT(cg->bit));
++}
++
++static void mtk_cg_clr_bit(struct clk_hw *hw)
++{
++ struct mtk_clk_gate *cg = to_clk_gate(hw);
++
++ regmap_write(cg->regmap, cg->clr_ofs, BIT(cg->bit));
++}
++
++static int mtk_cg_enable(struct clk_hw *hw)
++{
++ mtk_cg_clr_bit(hw);
++
++ return 0;
++}
++
++static void mtk_cg_disable(struct clk_hw *hw)
++{
++ mtk_cg_set_bit(hw);
++}
++
++static int mtk_cg_enable_inv(struct clk_hw *hw)
++{
++ mtk_cg_set_bit(hw);
++
++ return 0;
++}
++
++static void mtk_cg_disable_inv(struct clk_hw *hw)
++{
++ mtk_cg_clr_bit(hw);
++}
++
++const struct clk_ops mtk_clk_gate_ops_setclr = {
++ .is_enabled = mtk_cg_bit_is_cleared,
++ .enable = mtk_cg_enable,
++ .disable = mtk_cg_disable,
++};
++
++const struct clk_ops mtk_clk_gate_ops_setclr_inv = {
++ .is_enabled = mtk_cg_bit_is_set,
++ .enable = mtk_cg_enable_inv,
++ .disable = mtk_cg_disable_inv,
++};
++
++struct clk *mtk_clk_register_gate(
++ const char *name,
++ const char *parent_name,
++ struct regmap *regmap,
++ int set_ofs,
++ int clr_ofs,
++ int sta_ofs,
++ u8 bit,
++ const struct clk_ops *ops)
++{
++ struct mtk_clk_gate *cg;
++ struct clk *clk;
++ struct clk_init_data init;
++
++ cg = kzalloc(sizeof(*cg), GFP_KERNEL);
++ if (!cg)
++ return ERR_PTR(-ENOMEM);
++
++ init.name = name;
++ init.flags = CLK_SET_RATE_PARENT;
++ init.parent_names = parent_name ? &parent_name : NULL;
++ init.num_parents = parent_name ? 1 : 0;
++ init.ops = ops;
++
++ cg->regmap = regmap;
++ cg->set_ofs = set_ofs;
++ cg->clr_ofs = clr_ofs;
++ cg->sta_ofs = sta_ofs;
++ cg->bit = bit;
++
++ cg->hw.init = &init;
++
++ clk = clk_register(NULL, &cg->hw);
++ if (IS_ERR(clk))
++ kfree(cg);
++
++ return clk;
++}
+diff --git a/drivers/clk/mediatek/clk-gate.h b/drivers/clk/mediatek/clk-gate.h
+new file mode 100644
+index 0000000..6b6780b
+--- /dev/null
++++ b/drivers/clk/mediatek/clk-gate.h
+@@ -0,0 +1,49 @@
++/*
++ * Copyright (c) 2014 MediaTek Inc.
++ * Author: James Liao <jamesjj.liao@mediatek.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#ifndef __DRV_CLK_GATE_H
++#define __DRV_CLK_GATE_H
++
++#include <linux/regmap.h>
++#include <linux/clk.h>
++#include <linux/clk-provider.h>
++
++struct mtk_clk_gate {
++ struct clk_hw hw;
++ struct regmap *regmap;
++ int set_ofs;
++ int clr_ofs;
++ int sta_ofs;
++ u8 bit;
++};
++
++static inline struct mtk_clk_gate *to_clk_gate(struct clk_hw *hw)
++{
++ return container_of(hw, struct mtk_clk_gate, hw);
++}
++
++extern const struct clk_ops mtk_clk_gate_ops_setclr;
++extern const struct clk_ops mtk_clk_gate_ops_setclr_inv;
++
++struct clk *mtk_clk_register_gate(
++ const char *name,
++ const char *parent_name,
++ struct regmap *regmap,
++ int set_ofs,
++ int clr_ofs,
++ int sta_ofs,
++ u8 bit,
++ const struct clk_ops *ops);
++
++#endif /* __DRV_CLK_GATE_H */
+diff --git a/drivers/clk/mediatek/clk-mtk.c b/drivers/clk/mediatek/clk-mtk.c
+new file mode 100644
+index 0000000..18444ae
+--- /dev/null
++++ b/drivers/clk/mediatek/clk-mtk.c
+@@ -0,0 +1,220 @@
++/*
++ * Copyright (c) 2014 MediaTek Inc.
++ * Author: James Liao <jamesjj.liao@mediatek.com>
++ *
++ * 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.
++ */
++
++#include <linux/of.h>
++#include <linux/of_address.h>
++#include <linux/err.h>
++#include <linux/io.h>
++#include <linux/slab.h>
++#include <linux/delay.h>
++#include <linux/clkdev.h>
++#include <linux/mfd/syscon.h>
++
++#include "clk-mtk.h"
++#include "clk-gate.h"
++
++struct clk_onecell_data *mtk_alloc_clk_data(unsigned int clk_num)
++{
++ int i;
++ struct clk_onecell_data *clk_data;
++
++ clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
++ if (!clk_data)
++ return NULL;
++
++ clk_data->clks = kcalloc(clk_num, sizeof(*clk_data->clks), GFP_KERNEL);
++ if (!clk_data->clks)
++ goto err_out;
++
++ clk_data->clk_num = clk_num;
++
++ for (i = 0; i < clk_num; i++)
++ clk_data->clks[i] = ERR_PTR(-ENOENT);
++
++ return clk_data;
++err_out:
++ kfree(clk_data);
++
++ return NULL;
++}
++
++void mtk_clk_register_factors(const struct mtk_fixed_factor *clks, int num,
++ struct clk_onecell_data *clk_data)
++{
++ int i;
++ struct clk *clk;
++
++ for (i = 0; i < num; i++) {
++ const struct mtk_fixed_factor *ff = &clks[i];
++
++ clk = clk_register_fixed_factor(NULL, ff->name, ff->parent_name,
++ CLK_SET_RATE_PARENT, ff->mult, ff->div);
++
++ if (IS_ERR(clk)) {
++ pr_err("Failed to register clk %s: %ld\n",
++ ff->name, PTR_ERR(clk));
++ continue;
++ }
++
++ if (clk_data)
++ clk_data->clks[ff->id] = clk;
++ }
++}
++
++int mtk_clk_register_gates(struct device_node *node, const struct mtk_gate *clks,
++ int num, struct clk_onecell_data *clk_data)
++{
++ int i;
++ struct clk *clk;
++ struct regmap *regmap;
++
++ if (!clk_data)
++ return -ENOMEM;
++
++ regmap = syscon_node_to_regmap(node);
++ if (IS_ERR(regmap)) {
++ pr_err("Cannot find regmap for %s: %ld\n", node->full_name,
++ PTR_ERR(regmap));
++ return PTR_ERR(regmap);
++ }
++
++ for (i = 0; i < num; i++) {
++ const struct mtk_gate *gate = &clks[i];
++
++ clk = mtk_clk_register_gate(gate->name, gate->parent_name,
++ regmap,
++ gate->regs->set_ofs,
++ gate->regs->clr_ofs,
++ gate->regs->sta_ofs,
++ gate->shift, gate->ops);
++
++ if (IS_ERR(clk)) {
++ pr_err("Failed to register clk %s: %ld\n",
++ gate->name, PTR_ERR(clk));
++ continue;
++ }
++
++ clk_data->clks[gate->id] = clk;
++ }
++
++ return 0;
++}
++
++struct clk *mtk_clk_register_composite(const struct mtk_composite *mc,
++ void __iomem *base, spinlock_t *lock)
++{
++ struct clk *clk;
++ struct clk_mux *mux = NULL;
++ struct clk_gate *gate = NULL;
++ struct clk_divider *div = NULL;
++ struct clk_hw *mux_hw = NULL, *gate_hw = NULL, *div_hw = NULL;
++ const struct clk_ops *mux_ops = NULL, *gate_ops = NULL, *div_ops = NULL;
++ const char * const *parent_names;
++ const char *parent;
++ int num_parents;
++ int ret;
++
++ if (mc->mux_shift >= 0) {
++ mux = kzalloc(sizeof(*mux), GFP_KERNEL);
++ if (!mux)
++ return ERR_PTR(-ENOMEM);
++
++ mux->reg = base + mc->mux_reg;
++ mux->mask = BIT(mc->mux_width) - 1;
++ mux->shift = mc->mux_shift;
++ mux->lock = lock;
++
++ mux_hw = &mux->hw;
++ mux_ops = &clk_mux_ops;
++
++ parent_names = mc->parent_names;
++ num_parents = mc->num_parents;
++ } else {
++ parent = mc->parent;
++ parent_names = &parent;
++ num_parents = 1;
++ }
++
++ if (mc->gate_shift >= 0) {
++ gate = kzalloc(sizeof(*gate), GFP_KERNEL);
++ if (!gate) {
++ ret = -ENOMEM;
++ goto err_out;
++ }
++
++ gate->reg = base + mc->gate_reg;
++ gate->bit_idx = mc->gate_shift;
++ gate->flags = CLK_GATE_SET_TO_DISABLE;
++ gate->lock = lock;
++
++ gate_hw = &gate->hw;
++ gate_ops = &clk_gate_ops;
++ }
++
++ if (mc->divider_shift >= 0) {
++ div = kzalloc(sizeof(*div), GFP_KERNEL);
++ if (!div) {
++ ret = -ENOMEM;
++ goto err_out;
++ }
++
++ div->reg = base + mc->divider_reg;
++ div->shift = mc->divider_shift;
++ div->width = mc->divider_width;
++ div->lock = lock;
++
++ div_hw = &div->hw;
++ div_ops = &clk_divider_ops;
++ }
++
++ clk = clk_register_composite(NULL, mc->name, parent_names, num_parents,
++ mux_hw, mux_ops,
++ div_hw, div_ops,
++ gate_hw, gate_ops,
++ mc->flags);
++
++ if (IS_ERR(clk)) {
++ kfree(gate);
++ kfree(mux);
++ }
++
++ return clk;
++err_out:
++ kfree(mux);
++
++ return ERR_PTR(ret);
++}
++
++void mtk_clk_register_composites(const struct mtk_composite *mcs,
++ int num, void __iomem *base, spinlock_t *lock,
++ struct clk_onecell_data *clk_data)
++{
++ struct clk *clk;
++ int i;
++
++ for (i = 0; i < num; i++) {
++ const struct mtk_composite *mc = &mcs[i];
++
++ clk = mtk_clk_register_composite(mc, base, lock);
++
++ if (IS_ERR(clk)) {
++ pr_err("Failed to register clk %s: %ld\n",
++ mc->name, PTR_ERR(clk));
++ continue;
++ }
++
++ if (clk_data)
++ clk_data->clks[mc->id] = clk;
++ }
++}
+diff --git a/drivers/clk/mediatek/clk-mtk.h b/drivers/clk/mediatek/clk-mtk.h
+new file mode 100644
+index 0000000..694fc39
+--- /dev/null
++++ b/drivers/clk/mediatek/clk-mtk.h
+@@ -0,0 +1,159 @@
++/*
++ * Copyright (c) 2014 MediaTek Inc.
++ * Author: James Liao <jamesjj.liao@mediatek.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#ifndef __DRV_CLK_MTK_H
++#define __DRV_CLK_MTK_H
++
++#include <linux/regmap.h>
++#include <linux/bitops.h>
++#include <linux/clk.h>
++#include <linux/clk-provider.h>
++
++#define MAX_MUX_GATE_BIT 31
++#define INVALID_MUX_GATE_BIT (MAX_MUX_GATE_BIT + 1)
++
++#define MHZ (1000 * 1000)
++
++struct mtk_fixed_factor {
++ int id;
++ const char *name;
++ const char *parent_name;
++ int mult;
++ int div;
++};
++
++#define FACTOR(_id, _name, _parent, _mult, _div) { \
++ .id = _id, \
++ .name = _name, \
++ .parent_name = _parent, \
++ .mult = _mult, \
++ .div = _div, \
++ }
++
++extern void mtk_clk_register_factors(const struct mtk_fixed_factor *clks,
++ int num, struct clk_onecell_data *clk_data);
++
++struct mtk_composite {
++ int id;
++ const char *name;
++ const char * const * parent_names;
++ const char *parent;
++ unsigned flags;
++
++ uint32_t mux_reg;
++ uint32_t divider_reg;
++ uint32_t gate_reg;
++
++ signed char mux_shift;
++ signed char mux_width;
++ signed char gate_shift;
++
++ signed char divider_shift;
++ signed char divider_width;
++
++ signed char num_parents;
++};
++
++#define MUX_GATE(_id, _name, _parents, _reg, _shift, _width, _gate) { \
++ .id = _id, \
++ .name = _name, \
++ .mux_reg = _reg, \
++ .mux_shift = _shift, \
++ .mux_width = _width, \
++ .gate_reg = _reg, \
++ .gate_shift = _gate, \
++ .divider_shift = -1, \
++ .parent_names = _parents, \
++ .num_parents = ARRAY_SIZE(_parents), \
++ .flags = CLK_SET_RATE_PARENT, \
++ }
++
++#define MUX(_id, _name, _parents, _reg, _shift, _width) { \
++ .id = _id, \
++ .name = _name, \
++ .mux_reg = _reg, \
++ .mux_shift = _shift, \
++ .mux_width = _width, \
++ .gate_shift = -1, \
++ .divider_shift = -1, \
++ .parent_names = _parents, \
++ .num_parents = ARRAY_SIZE(_parents), \
++ .flags = CLK_SET_RATE_PARENT, \
++ }
++
++#define DIV_GATE(_id, _name, _parent, _gate_reg, _gate_shift, _div_reg, _div_width, _div_shift) { \
++ .id = _id, \
++ .parent = _parent, \
++ .name = _name, \
++ .divider_reg = _div_reg, \
++ .divider_shift = _div_shift, \
++ .divider_width = _div_width, \
++ .gate_reg = _gate_reg, \
++ .gate_shift = _gate_shift, \
++ .mux_shift = -1, \
++ .flags = 0, \
++ }
++
++struct clk *mtk_clk_register_composite(const struct mtk_composite *mc,
++ void __iomem *base, spinlock_t *lock);
++
++void mtk_clk_register_composites(const struct mtk_composite *mcs,
++ int num, void __iomem *base, spinlock_t *lock,
++ struct clk_onecell_data *clk_data);
++
++struct mtk_gate_regs {
++ u32 sta_ofs;
++ u32 clr_ofs;
++ u32 set_ofs;
++};
++
++struct mtk_gate {
++ int id;
++ const char *name;
++ const char *parent_name;
++ const struct mtk_gate_regs *regs;
++ int shift;
++ const struct clk_ops *ops;
++};
++
++int mtk_clk_register_gates(struct device_node *node, const struct mtk_gate *clks,
++ int num, struct clk_onecell_data *clk_data);
++
++struct clk_onecell_data *mtk_alloc_clk_data(unsigned int clk_num);
++
++#define HAVE_RST_BAR BIT(0)
++
++struct mtk_pll_data {
++ int id;
++ const char *name;
++ uint32_t reg;
++ uint32_t pwr_reg;
++ uint32_t en_mask;
++ uint32_t pd_reg;
++ uint32_t tuner_reg;
++ int pd_shift;
++ unsigned int flags;
++ const struct clk_ops *ops;
++ u32 rst_bar_mask;
++ unsigned long fmax;
++ int pcwbits;
++ uint32_t pcw_reg;
++ int pcw_shift;
++};
++
++void __init mtk_clk_register_plls(struct device_node *node,
++ const struct mtk_pll_data *plls, int num_plls,
++ struct clk_onecell_data *clk_data);
++
++#endif /* __DRV_CLK_MTK_H */
+diff --git a/drivers/clk/mediatek/clk-pll.c b/drivers/clk/mediatek/clk-pll.c
+new file mode 100644
+index 0000000..66154ca
+--- /dev/null
++++ b/drivers/clk/mediatek/clk-pll.c
+@@ -0,0 +1,332 @@
++/*
++ * Copyright (c) 2014 MediaTek Inc.
++ * Author: James Liao <jamesjj.liao@mediatek.com>
++ *
++ * 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.
++ */
++
++#include <linux/of.h>
++#include <linux/of_address.h>
++#include <linux/io.h>
++#include <linux/slab.h>
++#include <linux/clkdev.h>
++#include <linux/delay.h>
++
++#include "clk-mtk.h"
++
++#define REG_CON0 0
++#define REG_CON1 4
++
++#define CON0_BASE_EN BIT(0)
++#define CON0_PWR_ON BIT(0)
++#define CON0_ISO_EN BIT(1)
++#define CON0_PCW_CHG BIT(31)
++
++#define AUDPLL_TUNER_EN BIT(31)
++
++#define POSTDIV_MASK 0x7
++#define INTEGER_BITS 7
++
++/*
++ * MediaTek PLLs are configured through their pcw value. The pcw value describes
++ * a divider in the PLL feedback loop which consists of 7 bits for the integer
++ * part and the remaining bits (if present) for the fractional part. Also they
++ * have a 3 bit power-of-two post divider.
++ */
++
++struct mtk_clk_pll {
++ struct clk_hw hw;
++ void __iomem *base_addr;
++ void __iomem *pd_addr;
++ void __iomem *pwr_addr;
++ void __iomem *tuner_addr;
++ void __iomem *pcw_addr;
++ const struct mtk_pll_data *data;
++};
++
++static inline struct mtk_clk_pll *to_mtk_clk_pll(struct clk_hw *hw)
++{
++ return container_of(hw, struct mtk_clk_pll, hw);
++}
++
++static int mtk_pll_is_prepared(struct clk_hw *hw)
++{
++ struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
++
++ return (readl(pll->base_addr + REG_CON0) & CON0_BASE_EN) != 0;
++}
++
++static unsigned long __mtk_pll_recalc_rate(struct mtk_clk_pll *pll, u32 fin,
++ u32 pcw, int postdiv)
++{
++ int pcwbits = pll->data->pcwbits;
++ int pcwfbits;
++ u64 vco;
++ u8 c = 0;
++
++ /* The fractional part of the PLL divider. */
++ pcwfbits = pcwbits > INTEGER_BITS ? pcwbits - INTEGER_BITS : 0;
++
++ vco = (u64)fin * pcw;
++
++ if (pcwfbits && (vco & GENMASK(pcwfbits - 1, 0)))
++ c = 1;
++
++ vco >>= pcwfbits;
++
++ if (c)
++ vco++;
++
++ return ((unsigned long)vco + postdiv - 1) / postdiv;
++}
++
++static void mtk_pll_set_rate_regs(struct mtk_clk_pll *pll, u32 pcw,
++ int postdiv)
++{
++ u32 con1, pd, val;
++ int pll_en;
++
++ /* set postdiv */
++ pd = readl(pll->pd_addr);
++ pd &= ~(POSTDIV_MASK << pll->data->pd_shift);
++ pd |= (ffs(postdiv) - 1) << pll->data->pd_shift;
++ writel(pd, pll->pd_addr);
++
++ pll_en = readl(pll->base_addr + REG_CON0) & CON0_BASE_EN;
++
++ /* set pcw */
++ val = readl(pll->pcw_addr);
++
++ val &= ~GENMASK(pll->data->pcw_shift + pll->data->pcwbits - 1,
++ pll->data->pcw_shift);
++ val |= pcw << pll->data->pcw_shift;
++ writel(val, pll->pcw_addr);
++
++ con1 = readl(pll->base_addr + REG_CON1);
++
++ if (pll_en)
++ con1 |= CON0_PCW_CHG;
++
++ writel(con1, pll->base_addr + REG_CON1);
++ if (pll->tuner_addr)
++ writel(con1 + 1, pll->tuner_addr);
++
++ if (pll_en)
++ udelay(20);
++}
++
++/*
++ * mtk_pll_calc_values - calculate good values for a given input frequency.
++ * @pll: The pll
++ * @pcw: The pcw value (output)
++ * @postdiv: The post divider (output)
++ * @freq: The desired target frequency
++ * @fin: The input frequency
++ *
++ */
++static void mtk_pll_calc_values(struct mtk_clk_pll *pll, u32 *pcw, u32 *postdiv,
++ u32 freq, u32 fin)
++{
++ unsigned long fmin = 1000 * MHZ;
++ u64 _pcw;
++ u32 val;
++
++ if (freq > pll->data->fmax)
++ freq = pll->data->fmax;
++
++ for (val = 0; val < 4; val++) {
++ *postdiv = 1 << val;
++ if (freq * *postdiv >= fmin)
++ break;
++ }
++
++ /* _pcw = freq * postdiv / fin * 2^pcwfbits */
++ _pcw = ((u64)freq << val) << (pll->data->pcwbits - INTEGER_BITS);
++ do_div(_pcw, fin);
++
++ *pcw = (u32)_pcw;
++}
++
++static int mtk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
++ unsigned long parent_rate)
++{
++ struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
++ u32 pcw = 0;
++ u32 postdiv;
++
++ mtk_pll_calc_values(pll, &pcw, &postdiv, rate, parent_rate);
++ mtk_pll_set_rate_regs(pll, pcw, postdiv);
++
++ return 0;
++}
++
++static unsigned long mtk_pll_recalc_rate(struct clk_hw *hw,
++ unsigned long parent_rate)
++{
++ struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
++ u32 postdiv;
++ u32 pcw;
++
++ postdiv = (readl(pll->pd_addr) >> pll->data->pd_shift) & POSTDIV_MASK;
++ postdiv = 1 << postdiv;
++
++ pcw = readl(pll->pcw_addr) >> pll->data->pcw_shift;
++ pcw &= GENMASK(pll->data->pcwbits - 1, 0);
++
++ return __mtk_pll_recalc_rate(pll, parent_rate, pcw, postdiv);
++}
++
++static long mtk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
++ unsigned long *prate)
++{
++ struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
++ u32 pcw = 0;
++ int postdiv;
++
++ mtk_pll_calc_values(pll, &pcw, &postdiv, rate, *prate);
++
++ return __mtk_pll_recalc_rate(pll, *prate, pcw, postdiv);
++}
++
++static int mtk_pll_prepare(struct clk_hw *hw)
++{
++ struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
++ u32 r;
++
++ r = readl(pll->pwr_addr) | CON0_PWR_ON;
++ writel(r, pll->pwr_addr);
++ udelay(1);
++
++ r = readl(pll->pwr_addr) & ~CON0_ISO_EN;
++ writel(r, pll->pwr_addr);
++ udelay(1);
++
++ r = readl(pll->base_addr + REG_CON0);
++ r |= pll->data->en_mask;
++ writel(r, pll->base_addr + REG_CON0);
++
++ if (pll->tuner_addr) {
++ r = readl(pll->tuner_addr) | AUDPLL_TUNER_EN;
++ writel(r, pll->tuner_addr);
++ }
++
++ udelay(20);
++
++ if (pll->data->flags & HAVE_RST_BAR) {
++ r = readl(pll->base_addr + REG_CON0);
++ r |= pll->data->rst_bar_mask;
++ writel(r, pll->base_addr + REG_CON0);
++ }
++
++ return 0;
++}
++
++static void mtk_pll_unprepare(struct clk_hw *hw)
++{
++ struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
++ u32 r;
++
++ if (pll->data->flags & HAVE_RST_BAR) {
++ r = readl(pll->base_addr + REG_CON0);
++ r &= ~pll->data->rst_bar_mask;
++ writel(r, pll->base_addr + REG_CON0);
++ }
++
++ if (pll->tuner_addr) {
++ r = readl(pll->tuner_addr) & ~AUDPLL_TUNER_EN;
++ writel(r, pll->tuner_addr);
++ }
++
++ r = readl(pll->base_addr + REG_CON0);
++ r &= ~CON0_BASE_EN;
++ writel(r, pll->base_addr + REG_CON0);
++
++ r = readl(pll->pwr_addr) | CON0_ISO_EN;
++ writel(r, pll->pwr_addr);
++
++ r = readl(pll->pwr_addr) & ~CON0_PWR_ON;
++ writel(r, pll->pwr_addr);
++}
++
++static const struct clk_ops mtk_pll_ops = {
++ .is_prepared = mtk_pll_is_prepared,
++ .prepare = mtk_pll_prepare,
++ .unprepare = mtk_pll_unprepare,
++ .recalc_rate = mtk_pll_recalc_rate,
++ .round_rate = mtk_pll_round_rate,
++ .set_rate = mtk_pll_set_rate,
++};
++
++static struct clk *mtk_clk_register_pll(const struct mtk_pll_data *data,
++ void __iomem *base)
++{
++ struct mtk_clk_pll *pll;
++ struct clk_init_data init;
++ struct clk *clk;
++ const char *parent_name = "clk26m";
++
++ pll = kzalloc(sizeof(*pll), GFP_KERNEL);
++ if (!pll)
++ return ERR_PTR(-ENOMEM);
++
++ pll->base_addr = base + data->reg;
++ pll->pwr_addr = base + data->pwr_reg;
++ pll->pd_addr = base + data->pd_reg;
++ pll->pcw_addr = base + data->pcw_reg;
++ if (data->tuner_reg)
++ pll->tuner_addr = base + data->tuner_reg;
++ pll->hw.init = &init;
++ pll->data = data;
++
++ init.name = data->name;
++ init.ops = &mtk_pll_ops;
++ init.parent_names = &parent_name;
++ init.num_parents = 1;
++
++ clk = clk_register(NULL, &pll->hw);
++
++ if (IS_ERR(clk))
++ kfree(pll);
++
++ return clk;
++}
++
++void __init mtk_clk_register_plls(struct device_node *node,
++ const struct mtk_pll_data *plls, int num_plls, struct clk_onecell_data *clk_data)
++{
++ void __iomem *base;
++ int r, i;
++ struct clk *clk;
++
++ base = of_iomap(node, 0);
++ if (!base) {
++ pr_err("%s(): ioremap failed\n", __func__);
++ return;
++ }
++
++ for (i = 0; i < num_plls; i++) {
++ const struct mtk_pll_data *pll = &plls[i];
++
++ clk = mtk_clk_register_pll(pll, base);
++
++ if (IS_ERR(clk)) {
++ pr_err("Failed to register clk %s: %ld\n",
++ pll->name, PTR_ERR(clk));
++ continue;
++ }
++
++ clk_data->clks[pll->id] = clk;
++ }
++
++ r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
++ if (r)
++ pr_err("%s(): could not register clock provider: %d\n",
++ __func__, r);
++}
+--
+1.7.10.4
+
--- /dev/null
+From c91e8490e45c68ea517f70f24568034b7735e8b9 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer@pengutronix.de>
+Date: Thu, 23 Apr 2015 10:35:40 +0200
+Subject: [PATCH 03/76] clk: mediatek: Add reset controller support
+
+The pericfg and infracfg units also provide reset lines to several
+other SoC internal units. This adds a function which can be called
+from the pericfg and infracfg initialization functions which will
+register the reset controller using reset_controller_register. The
+reset controller will provide support for resetting the units
+connected to the pericfg and infracfg controller. The units resetted
+by this controller can use the standard reset device tree binding
+to gain access to the reset lines.
+
+Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
+Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
+---
+ drivers/clk/mediatek/Makefile | 1 +
+ drivers/clk/mediatek/clk-mtk.h | 10 +++++
+ drivers/clk/mediatek/reset.c | 97 ++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 108 insertions(+)
+ create mode 100644 drivers/clk/mediatek/reset.c
+
+diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile
+index c384e97..0b6f1c3 100644
+--- a/drivers/clk/mediatek/Makefile
++++ b/drivers/clk/mediatek/Makefile
+@@ -1 +1,2 @@
+ obj-y += clk-mtk.o clk-pll.o clk-gate.o
++obj-$(CONFIG_RESET_CONTROLLER) += reset.o
+diff --git a/drivers/clk/mediatek/clk-mtk.h b/drivers/clk/mediatek/clk-mtk.h
+index 694fc39..61035b9 100644
+--- a/drivers/clk/mediatek/clk-mtk.h
++++ b/drivers/clk/mediatek/clk-mtk.h
+@@ -156,4 +156,14 @@ void __init mtk_clk_register_plls(struct device_node *node,
+ const struct mtk_pll_data *plls, int num_plls,
+ struct clk_onecell_data *clk_data);
+
++#ifdef CONFIG_RESET_CONTROLLER
++void mtk_register_reset_controller(struct device_node *np,
++ unsigned int num_regs, int regofs);
++#else
++static inline void mtk_register_reset_controller(struct device_node *np,
++ unsigned int num_regs, int regofs)
++{
++}
++#endif
++
+ #endif /* __DRV_CLK_MTK_H */
+diff --git a/drivers/clk/mediatek/reset.c b/drivers/clk/mediatek/reset.c
+new file mode 100644
+index 0000000..9e9fe4b
+--- /dev/null
++++ b/drivers/clk/mediatek/reset.c
+@@ -0,0 +1,97 @@
++/*
++ * Copyright (c) 2014 MediaTek Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/mfd/syscon.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <linux/regmap.h>
++#include <linux/reset-controller.h>
++#include <linux/slab.h>
++
++#include "clk-mtk.h"
++
++struct mtk_reset {
++ struct regmap *regmap;
++ int regofs;
++ struct reset_controller_dev rcdev;
++};
++
++static int mtk_reset_assert(struct reset_controller_dev *rcdev,
++ unsigned long id)
++{
++ struct mtk_reset *data = container_of(rcdev, struct mtk_reset, rcdev);
++
++ return regmap_update_bits(data->regmap, data->regofs + ((id / 32) << 2),
++ BIT(id % 32), ~0);
++}
++
++static int mtk_reset_deassert(struct reset_controller_dev *rcdev,
++ unsigned long id)
++{
++ struct mtk_reset *data = container_of(rcdev, struct mtk_reset, rcdev);
++
++ return regmap_update_bits(data->regmap, data->regofs + ((id / 32) << 2),
++ BIT(id % 32), 0);
++}
++
++static int mtk_reset(struct reset_controller_dev *rcdev,
++ unsigned long id)
++{
++ int ret;
++
++ ret = mtk_reset_assert(rcdev, id);
++ if (ret)
++ return ret;
++
++ return mtk_reset_deassert(rcdev, id);
++}
++
++static struct reset_control_ops mtk_reset_ops = {
++ .assert = mtk_reset_assert,
++ .deassert = mtk_reset_deassert,
++ .reset = mtk_reset,
++};
++
++void mtk_register_reset_controller(struct device_node *np,
++ unsigned int num_regs, int regofs)
++{
++ struct mtk_reset *data;
++ int ret;
++ struct regmap *regmap;
++
++ regmap = syscon_node_to_regmap(np);
++ if (IS_ERR(regmap)) {
++ pr_err("Cannot find regmap for %s: %ld\n", np->full_name,
++ PTR_ERR(regmap));
++ return;
++ }
++
++ data = kzalloc(sizeof(*data), GFP_KERNEL);
++ if (!data)
++ return;
++
++ data->regmap = regmap;
++ data->regofs = regofs;
++ data->rcdev.owner = THIS_MODULE;
++ data->rcdev.nr_resets = num_regs * 32;
++ data->rcdev.ops = &mtk_reset_ops;
++ data->rcdev.of_node = np;
++
++ ret = reset_controller_register(&data->rcdev);
++ if (ret) {
++ pr_err("could not register reset controller: %d\n", ret);
++ kfree(data);
++ return;
++ }
++}
+--
+1.7.10.4
+
--- /dev/null
+From 242572135fdb513cba0506415c7e26a0909eb4b5 Mon Sep 17 00:00:00 2001
+From: James Liao <jamesjj.liao@mediatek.com>
+Date: Thu, 23 Apr 2015 10:35:41 +0200
+Subject: [PATCH 04/76] clk: mediatek: Add basic clocks for Mediatek MT8135.
+
+This patch adds basic clocks for MT8135, including TOPCKGEN, PLLs,
+INFRA and PERI clocks.
+
+Signed-off-by: James Liao <jamesjj.liao@mediatek.com>
+Signed-off-by: Henry Chen <henryc.chen@mediatek.com>
+Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
+---
+ drivers/clk/mediatek/Makefile | 1 +
+ drivers/clk/mediatek/clk-mt8135.c | 644 ++++++++++++++++++++
+ include/dt-bindings/clock/mt8135-clk.h | 194 ++++++
+ .../dt-bindings/reset-controller/mt8135-resets.h | 64 ++
+ 4 files changed, 903 insertions(+)
+ create mode 100644 drivers/clk/mediatek/clk-mt8135.c
+ create mode 100644 include/dt-bindings/clock/mt8135-clk.h
+ create mode 100644 include/dt-bindings/reset-controller/mt8135-resets.h
+
+diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile
+index 0b6f1c3..12ce576 100644
+--- a/drivers/clk/mediatek/Makefile
++++ b/drivers/clk/mediatek/Makefile
+@@ -1,2 +1,3 @@
+ obj-y += clk-mtk.o clk-pll.o clk-gate.o
+ obj-$(CONFIG_RESET_CONTROLLER) += reset.o
++obj-y += clk-mt8135.o
+diff --git a/drivers/clk/mediatek/clk-mt8135.c b/drivers/clk/mediatek/clk-mt8135.c
+new file mode 100644
+index 0000000..a63435b
+--- /dev/null
++++ b/drivers/clk/mediatek/clk-mt8135.c
+@@ -0,0 +1,644 @@
++/*
++ * Copyright (c) 2014 MediaTek Inc.
++ * Author: James Liao <jamesjj.liao@mediatek.com>
++ *
++ * 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.
++ */
++
++#include <linux/of.h>
++#include <linux/of_address.h>
++#include <linux/slab.h>
++#include <linux/mfd/syscon.h>
++#include <dt-bindings/clock/mt8135-clk.h>
++
++#include "clk-mtk.h"
++#include "clk-gate.h"
++
++static DEFINE_SPINLOCK(mt8135_clk_lock);
++
++static const struct mtk_fixed_factor root_clk_alias[] __initconst = {
++ FACTOR(CLK_TOP_DSI0_LNTC_DSICLK, "dsi0_lntc_dsiclk", "clk_null", 1, 1),
++ FACTOR(CLK_TOP_HDMITX_CLKDIG_CTS, "hdmitx_clkdig_cts", "clk_null", 1, 1),
++ FACTOR(CLK_TOP_CLKPH_MCK, "clkph_mck", "clk_null", 1, 1),
++ FACTOR(CLK_TOP_CPUM_TCK_IN, "cpum_tck_in", "clk_null", 1, 1),
++};
++
++static const struct mtk_fixed_factor top_divs[] __initconst = {
++ FACTOR(CLK_TOP_MAINPLL_806M, "mainpll_806m", "mainpll", 1, 2),
++ FACTOR(CLK_TOP_MAINPLL_537P3M, "mainpll_537p3m", "mainpll", 1, 3),
++ FACTOR(CLK_TOP_MAINPLL_322P4M, "mainpll_322p4m", "mainpll", 1, 5),
++ FACTOR(CLK_TOP_MAINPLL_230P3M, "mainpll_230p3m", "mainpll", 1, 7),
++
++ FACTOR(CLK_TOP_UNIVPLL_624M, "univpll_624m", "univpll", 1, 2),
++ FACTOR(CLK_TOP_UNIVPLL_416M, "univpll_416m", "univpll", 1, 3),
++ FACTOR(CLK_TOP_UNIVPLL_249P6M, "univpll_249p6m", "univpll", 1, 5),
++ FACTOR(CLK_TOP_UNIVPLL_178P3M, "univpll_178p3m", "univpll", 1, 7),
++ FACTOR(CLK_TOP_UNIVPLL_48M, "univpll_48m", "univpll", 1, 26),
++
++ FACTOR(CLK_TOP_MMPLL_D2, "mmpll_d2", "mmpll", 1, 2),
++ FACTOR(CLK_TOP_MMPLL_D3, "mmpll_d3", "mmpll", 1, 3),
++ FACTOR(CLK_TOP_MMPLL_D5, "mmpll_d5", "mmpll", 1, 5),
++ FACTOR(CLK_TOP_MMPLL_D7, "mmpll_d7", "mmpll", 1, 7),
++ FACTOR(CLK_TOP_MMPLL_D4, "mmpll_d4", "mmpll_d2", 1, 2),
++ FACTOR(CLK_TOP_MMPLL_D6, "mmpll_d6", "mmpll_d3", 1, 2),
++
++ FACTOR(CLK_TOP_SYSPLL_D2, "syspll_d2", "mainpll_806m", 1, 1),
++ FACTOR(CLK_TOP_SYSPLL_D4, "syspll_d4", "mainpll_806m", 1, 2),
++ FACTOR(CLK_TOP_SYSPLL_D6, "syspll_d6", "mainpll_806m", 1, 3),
++ FACTOR(CLK_TOP_SYSPLL_D8, "syspll_d8", "mainpll_806m", 1, 4),
++ FACTOR(CLK_TOP_SYSPLL_D10, "syspll_d10", "mainpll_806m", 1, 5),
++ FACTOR(CLK_TOP_SYSPLL_D12, "syspll_d12", "mainpll_806m", 1, 6),
++ FACTOR(CLK_TOP_SYSPLL_D16, "syspll_d16", "mainpll_806m", 1, 8),
++ FACTOR(CLK_TOP_SYSPLL_D24, "syspll_d24", "mainpll_806m", 1, 12),
++
++ FACTOR(CLK_TOP_SYSPLL_D3, "syspll_d3", "mainpll_537p3m", 1, 1),
++
++ FACTOR(CLK_TOP_SYSPLL_D2P5, "syspll_d2p5", "mainpll_322p4m", 2, 1),
++ FACTOR(CLK_TOP_SYSPLL_D5, "syspll_d5", "mainpll_322p4m", 1, 1),
++
++ FACTOR(CLK_TOP_SYSPLL_D3P5, "syspll_d3p5", "mainpll_230p3m", 2, 1),
++
++ FACTOR(CLK_TOP_UNIVPLL1_D2, "univpll1_d2", "univpll_624m", 1, 2),
++ FACTOR(CLK_TOP_UNIVPLL1_D4, "univpll1_d4", "univpll_624m", 1, 4),
++ FACTOR(CLK_TOP_UNIVPLL1_D6, "univpll1_d6", "univpll_624m", 1, 6),
++ FACTOR(CLK_TOP_UNIVPLL1_D8, "univpll1_d8", "univpll_624m", 1, 8),
++ FACTOR(CLK_TOP_UNIVPLL1_D10, "univpll1_d10", "univpll_624m", 1, 10),
++
++ FACTOR(CLK_TOP_UNIVPLL2_D2, "univpll2_d2", "univpll_416m", 1, 2),
++ FACTOR(CLK_TOP_UNIVPLL2_D4, "univpll2_d4", "univpll_416m", 1, 4),
++ FACTOR(CLK_TOP_UNIVPLL2_D6, "univpll2_d6", "univpll_416m", 1, 6),
++ FACTOR(CLK_TOP_UNIVPLL2_D8, "univpll2_d8", "univpll_416m", 1, 8),
++
++ FACTOR(CLK_TOP_UNIVPLL_D3, "univpll_d3", "univpll_416m", 1, 1),
++ FACTOR(CLK_TOP_UNIVPLL_D5, "univpll_d5", "univpll_249p6m", 1, 1),
++ FACTOR(CLK_TOP_UNIVPLL_D7, "univpll_d7", "univpll_178p3m", 1, 1),
++ FACTOR(CLK_TOP_UNIVPLL_D10, "univpll_d10", "univpll_249p6m", 1, 2),
++ FACTOR(CLK_TOP_UNIVPLL_D26, "univpll_d26", "univpll_48m", 1, 1),
++
++ FACTOR(CLK_TOP_APLL, "apll_ck", "audpll", 1, 1),
++ FACTOR(CLK_TOP_APLL_D4, "apll_d4", "audpll", 1, 4),
++ FACTOR(CLK_TOP_APLL_D8, "apll_d8", "audpll", 1, 8),
++ FACTOR(CLK_TOP_APLL_D16, "apll_d16", "audpll", 1, 16),
++ FACTOR(CLK_TOP_APLL_D24, "apll_d24", "audpll", 1, 24),
++
++ FACTOR(CLK_TOP_LVDSPLL_D2, "lvdspll_d2", "lvdspll", 1, 2),
++ FACTOR(CLK_TOP_LVDSPLL_D4, "lvdspll_d4", "lvdspll", 1, 4),
++ FACTOR(CLK_TOP_LVDSPLL_D8, "lvdspll_d8", "lvdspll", 1, 8),
++
++ FACTOR(CLK_TOP_LVDSTX_CLKDIG_CT, "lvdstx_clkdig_cts", "lvdspll", 1, 1),
++ FACTOR(CLK_TOP_VPLL_DPIX, "vpll_dpix_ck", "lvdspll", 1, 1),
++
++ FACTOR(CLK_TOP_TVHDMI_H, "tvhdmi_h_ck", "tvdpll", 1, 1),
++
++ FACTOR(CLK_TOP_HDMITX_CLKDIG_D2, "hdmitx_clkdig_d2", "hdmitx_clkdig_cts", 1, 2),
++ FACTOR(CLK_TOP_HDMITX_CLKDIG_D3, "hdmitx_clkdig_d3", "hdmitx_clkdig_cts", 1, 3),
++
++ FACTOR(CLK_TOP_TVHDMI_D2, "tvhdmi_d2", "tvhdmi_h_ck", 1, 2),
++ FACTOR(CLK_TOP_TVHDMI_D4, "tvhdmi_d4", "tvhdmi_h_ck", 1, 4),
++
++ FACTOR(CLK_TOP_MEMPLL_MCK_D4, "mempll_mck_d4", "clkph_mck", 1, 4),
++};
++
++static const char * const axi_parents[] __initconst = {
++ "clk26m",
++ "syspll_d3",
++ "syspll_d4",
++ "syspll_d6",
++ "univpll_d5",
++ "univpll2_d2",
++ "syspll_d3p5"
++};
++
++static const char * const smi_parents[] __initconst = {
++ "clk26m",
++ "clkph_mck",
++ "syspll_d2p5",
++ "syspll_d3",
++ "syspll_d8",
++ "univpll_d5",
++ "univpll1_d2",
++ "univpll1_d6",
++ "mmpll_d3",
++ "mmpll_d4",
++ "mmpll_d5",
++ "mmpll_d6",
++ "mmpll_d7",
++ "vdecpll",
++ "lvdspll"
++};
++
++static const char * const mfg_parents[] __initconst = {
++ "clk26m",
++ "univpll1_d4",
++ "syspll_d2",
++ "syspll_d2p5",
++ "syspll_d3",
++ "univpll_d5",
++ "univpll1_d2",
++ "mmpll_d2",
++ "mmpll_d3",
++ "mmpll_d4",
++ "mmpll_d5",
++ "mmpll_d6",
++ "mmpll_d7"
++};
++
++static const char * const irda_parents[] __initconst = {
++ "clk26m",
++ "univpll2_d8",
++ "univpll1_d6"
++};
++
++static const char * const cam_parents[] __initconst = {
++ "clk26m",
++ "syspll_d3",
++ "syspll_d3p5",
++ "syspll_d4",
++ "univpll_d5",
++ "univpll2_d2",
++ "univpll_d7",
++ "univpll1_d4"
++};
++
++static const char * const aud_intbus_parents[] __initconst = {
++ "clk26m",
++ "syspll_d6",
++ "univpll_d10"
++};
++
++static const char * const jpg_parents[] __initconst = {
++ "clk26m",
++ "syspll_d5",
++ "syspll_d4",
++ "syspll_d3",
++ "univpll_d7",
++ "univpll2_d2",
++ "univpll_d5"
++};
++
++static const char * const disp_parents[] __initconst = {
++ "clk26m",
++ "syspll_d3p5",
++ "syspll_d3",
++ "univpll2_d2",
++ "univpll_d5",
++ "univpll1_d2",
++ "lvdspll",
++ "vdecpll"
++};
++
++static const char * const msdc30_parents[] __initconst = {
++ "clk26m",
++ "syspll_d6",
++ "syspll_d5",
++ "univpll1_d4",
++ "univpll2_d4",
++ "msdcpll"
++};
++
++static const char * const usb20_parents[] __initconst = {
++ "clk26m",
++ "univpll2_d6",
++ "univpll1_d10"
++};
++
++static const char * const venc_parents[] __initconst = {
++ "clk26m",
++ "syspll_d3",
++ "syspll_d8",
++ "univpll_d5",
++ "univpll1_d6",
++ "mmpll_d4",
++ "mmpll_d5",
++ "mmpll_d6"
++};
++
++static const char * const spi_parents[] __initconst = {
++ "clk26m",
++ "syspll_d6",
++ "syspll_d8",
++ "syspll_d10",
++ "univpll1_d6",
++ "univpll1_d8"
++};
++
++static const char * const uart_parents[] __initconst = {
++ "clk26m",
++ "univpll2_d8"
++};
++
++static const char * const mem_parents[] __initconst = {
++ "clk26m",
++ "clkph_mck"
++};
++
++static const char * const camtg_parents[] __initconst = {
++ "clk26m",
++ "univpll_d26",
++ "univpll1_d6",
++ "syspll_d16",
++ "syspll_d8"
++};
++
++static const char * const audio_parents[] __initconst = {
++ "clk26m",
++ "syspll_d24"
++};
++
++static const char * const fix_parents[] __initconst = {
++ "rtc32k",
++ "clk26m",
++ "univpll_d5",
++ "univpll_d7",
++ "univpll1_d2",
++ "univpll1_d4",
++ "univpll1_d6",
++ "univpll1_d8"
++};
++
++static const char * const vdec_parents[] __initconst = {
++ "clk26m",
++ "vdecpll",
++ "clkph_mck",
++ "syspll_d2p5",
++ "syspll_d3",
++ "syspll_d3p5",
++ "syspll_d4",
++ "syspll_d5",
++ "syspll_d6",
++ "syspll_d8",
++ "univpll1_d2",
++ "univpll2_d2",
++ "univpll_d7",
++ "univpll_d10",
++ "univpll2_d4",
++ "lvdspll"
++};
++
++static const char * const ddrphycfg_parents[] __initconst = {
++ "clk26m",
++ "axi_sel",
++ "syspll_d12"
++};
++
++static const char * const dpilvds_parents[] __initconst = {
++ "clk26m",
++ "lvdspll",
++ "lvdspll_d2",
++ "lvdspll_d4",
++ "lvdspll_d8"
++};
++
++static const char * const pmicspi_parents[] __initconst = {
++ "clk26m",
++ "univpll2_d6",
++ "syspll_d8",
++ "syspll_d10",
++ "univpll1_d10",
++ "mempll_mck_d4",
++ "univpll_d26",
++ "syspll_d24"
++};
++
++static const char * const smi_mfg_as_parents[] __initconst = {
++ "clk26m",
++ "smi_sel",
++ "mfg_sel",
++ "mem_sel"
++};
++
++static const char * const gcpu_parents[] __initconst = {
++ "clk26m",
++ "syspll_d4",
++ "univpll_d7",
++ "syspll_d5",
++ "syspll_d6"
++};
++
++static const char * const dpi1_parents[] __initconst = {
++ "clk26m",
++ "tvhdmi_h_ck",
++ "tvhdmi_d2",
++ "tvhdmi_d4"
++};
++
++static const char * const cci_parents[] __initconst = {
++ "clk26m",
++ "mainpll_537p3m",
++ "univpll_d3",
++ "syspll_d2p5",
++ "syspll_d3",
++ "syspll_d5"
++};
++
++static const char * const apll_parents[] __initconst = {
++ "clk26m",
++ "apll_ck",
++ "apll_d4",
++ "apll_d8",
++ "apll_d16",
++ "apll_d24"
++};
++
++static const char * const hdmipll_parents[] __initconst = {
++ "clk26m",
++ "hdmitx_clkdig_cts",
++ "hdmitx_clkdig_d2",
++ "hdmitx_clkdig_d3"
++};
++
++static const struct mtk_composite top_muxes[] __initconst = {
++ /* CLK_CFG_0 */
++ MUX_GATE(CLK_TOP_AXI_SEL, "axi_sel", axi_parents,
++ 0x0140, 0, 3, INVALID_MUX_GATE_BIT),
++ MUX_GATE(CLK_TOP_SMI_SEL, "smi_sel", smi_parents, 0x0140, 8, 4, 15),
++ MUX_GATE(CLK_TOP_MFG_SEL, "mfg_sel", mfg_parents, 0x0140, 16, 4, 23),
++ MUX_GATE(CLK_TOP_IRDA_SEL, "irda_sel", irda_parents, 0x0140, 24, 2, 31),
++ /* CLK_CFG_1 */
++ MUX_GATE(CLK_TOP_CAM_SEL, "cam_sel", cam_parents, 0x0144, 0, 3, 7),
++ MUX_GATE(CLK_TOP_AUD_INTBUS_SEL, "aud_intbus_sel", aud_intbus_parents,
++ 0x0144, 8, 2, 15),
++ MUX_GATE(CLK_TOP_JPG_SEL, "jpg_sel", jpg_parents, 0x0144, 16, 3, 23),
++ MUX_GATE(CLK_TOP_DISP_SEL, "disp_sel", disp_parents, 0x0144, 24, 3, 31),
++ /* CLK_CFG_2 */
++ MUX_GATE(CLK_TOP_MSDC30_1_SEL, "msdc30_1_sel", msdc30_parents, 0x0148, 0, 3, 7),
++ MUX_GATE(CLK_TOP_MSDC30_2_SEL, "msdc30_2_sel", msdc30_parents, 0x0148, 8, 3, 15),
++ MUX_GATE(CLK_TOP_MSDC30_3_SEL, "msdc30_3_sel", msdc30_parents, 0x0148, 16, 3, 23),
++ MUX_GATE(CLK_TOP_MSDC30_4_SEL, "msdc30_4_sel", msdc30_parents, 0x0148, 24, 3, 31),
++ /* CLK_CFG_3 */
++ MUX_GATE(CLK_TOP_USB20_SEL, "usb20_sel", usb20_parents, 0x014c, 0, 2, 7),
++ /* CLK_CFG_4 */
++ MUX_GATE(CLK_TOP_VENC_SEL, "venc_sel", venc_parents, 0x0150, 8, 3, 15),
++ MUX_GATE(CLK_TOP_SPI_SEL, "spi_sel", spi_parents, 0x0150, 16, 3, 23),
++ MUX_GATE(CLK_TOP_UART_SEL, "uart_sel", uart_parents, 0x0150, 24, 2, 31),
++ /* CLK_CFG_6 */
++ MUX_GATE(CLK_TOP_MEM_SEL, "mem_sel", mem_parents, 0x0158, 0, 2, 7),
++ MUX_GATE(CLK_TOP_CAMTG_SEL, "camtg_sel", camtg_parents, 0x0158, 8, 3, 15),
++ MUX_GATE(CLK_TOP_AUDIO_SEL, "audio_sel", audio_parents, 0x0158, 24, 2, 31),
++ /* CLK_CFG_7 */
++ MUX_GATE(CLK_TOP_FIX_SEL, "fix_sel", fix_parents, 0x015c, 0, 3, 7),
++ MUX_GATE(CLK_TOP_VDEC_SEL, "vdec_sel", vdec_parents, 0x015c, 8, 4, 15),
++ MUX_GATE(CLK_TOP_DDRPHYCFG_SEL, "ddrphycfg_sel", ddrphycfg_parents,
++ 0x015c, 16, 2, 23),
++ MUX_GATE(CLK_TOP_DPILVDS_SEL, "dpilvds_sel", dpilvds_parents, 0x015c, 24, 3, 31),
++ /* CLK_CFG_8 */
++ MUX_GATE(CLK_TOP_PMICSPI_SEL, "pmicspi_sel", pmicspi_parents, 0x0164, 0, 3, 7),
++ MUX_GATE(CLK_TOP_MSDC30_0_SEL, "msdc30_0_sel", msdc30_parents, 0x0164, 8, 3, 15),
++ MUX_GATE(CLK_TOP_SMI_MFG_AS_SEL, "smi_mfg_as_sel", smi_mfg_as_parents,
++ 0x0164, 16, 2, 23),
++ MUX_GATE(CLK_TOP_GCPU_SEL, "gcpu_sel", gcpu_parents, 0x0164, 24, 3, 31),
++ /* CLK_CFG_9 */
++ MUX_GATE(CLK_TOP_DPI1_SEL, "dpi1_sel", dpi1_parents, 0x0168, 0, 2, 7),
++ MUX_GATE(CLK_TOP_CCI_SEL, "cci_sel", cci_parents, 0x0168, 8, 3, 15),
++ MUX_GATE(CLK_TOP_APLL_SEL, "apll_sel", apll_parents, 0x0168, 16, 3, 23),
++ MUX_GATE(CLK_TOP_HDMIPLL_SEL, "hdmipll_sel", hdmipll_parents, 0x0168, 24, 2, 31),
++};
++
++static const struct mtk_gate_regs infra_cg_regs = {
++ .set_ofs = 0x0040,
++ .clr_ofs = 0x0044,
++ .sta_ofs = 0x0048,
++};
++
++#define GATE_ICG(_id, _name, _parent, _shift) { \
++ .id = _id, \
++ .name = _name, \
++ .parent_name = _parent, \
++ .regs = &infra_cg_regs, \
++ .shift = _shift, \
++ .ops = &mtk_clk_gate_ops_setclr, \
++ }
++
++static const struct mtk_gate infra_clks[] __initconst = {
++ GATE_ICG(CLK_INFRA_PMIC_WRAP, "pmic_wrap_ck", "axi_sel", 23),
++ GATE_ICG(CLK_INFRA_PMICSPI, "pmicspi_ck", "pmicspi_sel", 22),
++ GATE_ICG(CLK_INFRA_CCIF1_AP_CTRL, "ccif1_ap_ctrl", "axi_sel", 21),
++ GATE_ICG(CLK_INFRA_CCIF0_AP_CTRL, "ccif0_ap_ctrl", "axi_sel", 20),
++ GATE_ICG(CLK_INFRA_KP, "kp_ck", "axi_sel", 16),
++ GATE_ICG(CLK_INFRA_CPUM, "cpum_ck", "cpum_tck_in", 15),
++ GATE_ICG(CLK_INFRA_M4U, "m4u_ck", "mem_sel", 8),
++ GATE_ICG(CLK_INFRA_MFGAXI, "mfgaxi_ck", "axi_sel", 7),
++ GATE_ICG(CLK_INFRA_DEVAPC, "devapc_ck", "axi_sel", 6),
++ GATE_ICG(CLK_INFRA_AUDIO, "audio_ck", "aud_intbus_sel", 5),
++ GATE_ICG(CLK_INFRA_MFG_BUS, "mfg_bus_ck", "axi_sel", 2),
++ GATE_ICG(CLK_INFRA_SMI, "smi_ck", "smi_sel", 1),
++ GATE_ICG(CLK_INFRA_DBGCLK, "dbgclk_ck", "axi_sel", 0),
++};
++
++static const struct mtk_gate_regs peri0_cg_regs = {
++ .set_ofs = 0x0008,
++ .clr_ofs = 0x0010,
++ .sta_ofs = 0x0018,
++};
++
++static const struct mtk_gate_regs peri1_cg_regs = {
++ .set_ofs = 0x000c,
++ .clr_ofs = 0x0014,
++ .sta_ofs = 0x001c,
++};
++
++#define GATE_PERI0(_id, _name, _parent, _shift) { \
++ .id = _id, \
++ .name = _name, \
++ .parent_name = _parent, \
++ .regs = &peri0_cg_regs, \
++ .shift = _shift, \
++ .ops = &mtk_clk_gate_ops_setclr, \
++ }
++
++#define GATE_PERI1(_id, _name, _parent, _shift) { \
++ .id = _id, \
++ .name = _name, \
++ .parent_name = _parent, \
++ .regs = &peri1_cg_regs, \
++ .shift = _shift, \
++ .ops = &mtk_clk_gate_ops_setclr, \
++ }
++
++static const struct mtk_gate peri_gates[] __initconst = {
++ /* PERI0 */
++ GATE_PERI0(CLK_PERI_I2C5, "i2c5_ck", "axi_sel", 31),
++ GATE_PERI0(CLK_PERI_I2C4, "i2c4_ck", "axi_sel", 30),
++ GATE_PERI0(CLK_PERI_I2C3, "i2c3_ck", "axi_sel", 29),
++ GATE_PERI0(CLK_PERI_I2C2, "i2c2_ck", "axi_sel", 28),
++ GATE_PERI0(CLK_PERI_I2C1, "i2c1_ck", "axi_sel", 27),
++ GATE_PERI0(CLK_PERI_I2C0, "i2c0_ck", "axi_sel", 26),
++ GATE_PERI0(CLK_PERI_UART3, "uart3_ck", "axi_sel", 25),
++ GATE_PERI0(CLK_PERI_UART2, "uart2_ck", "axi_sel", 24),
++ GATE_PERI0(CLK_PERI_UART1, "uart1_ck", "axi_sel", 23),
++ GATE_PERI0(CLK_PERI_UART0, "uart0_ck", "axi_sel", 22),
++ GATE_PERI0(CLK_PERI_IRDA, "irda_ck", "irda_sel", 21),
++ GATE_PERI0(CLK_PERI_NLI, "nli_ck", "axi_sel", 20),
++ GATE_PERI0(CLK_PERI_MD_HIF, "md_hif_ck", "axi_sel", 19),
++ GATE_PERI0(CLK_PERI_AP_HIF, "ap_hif_ck", "axi_sel", 18),
++ GATE_PERI0(CLK_PERI_MSDC30_3, "msdc30_3_ck", "msdc30_4_sel", 17),
++ GATE_PERI0(CLK_PERI_MSDC30_2, "msdc30_2_ck", "msdc30_3_sel", 16),
++ GATE_PERI0(CLK_PERI_MSDC30_1, "msdc30_1_ck", "msdc30_2_sel", 15),
++ GATE_PERI0(CLK_PERI_MSDC20_2, "msdc20_2_ck", "msdc30_1_sel", 14),
++ GATE_PERI0(CLK_PERI_MSDC20_1, "msdc20_1_ck", "msdc30_0_sel", 13),
++ GATE_PERI0(CLK_PERI_AP_DMA, "ap_dma_ck", "axi_sel", 12),
++ GATE_PERI0(CLK_PERI_USB1, "usb1_ck", "usb20_sel", 11),
++ GATE_PERI0(CLK_PERI_USB0, "usb0_ck", "usb20_sel", 10),
++ GATE_PERI0(CLK_PERI_PWM, "pwm_ck", "axi_sel", 9),
++ GATE_PERI0(CLK_PERI_PWM7, "pwm7_ck", "axi_sel", 8),
++ GATE_PERI0(CLK_PERI_PWM6, "pwm6_ck", "axi_sel", 7),
++ GATE_PERI0(CLK_PERI_PWM5, "pwm5_ck", "axi_sel", 6),
++ GATE_PERI0(CLK_PERI_PWM4, "pwm4_ck", "axi_sel", 5),
++ GATE_PERI0(CLK_PERI_PWM3, "pwm3_ck", "axi_sel", 4),
++ GATE_PERI0(CLK_PERI_PWM2, "pwm2_ck", "axi_sel", 3),
++ GATE_PERI0(CLK_PERI_PWM1, "pwm1_ck", "axi_sel", 2),
++ GATE_PERI0(CLK_PERI_THERM, "therm_ck", "axi_sel", 1),
++ GATE_PERI0(CLK_PERI_NFI, "nfi_ck", "axi_sel", 0),
++ /* PERI1 */
++ GATE_PERI1(CLK_PERI_USBSLV, "usbslv_ck", "axi_sel", 8),
++ GATE_PERI1(CLK_PERI_USB1_MCU, "usb1_mcu_ck", "axi_sel", 7),
++ GATE_PERI1(CLK_PERI_USB0_MCU, "usb0_mcu_ck", "axi_sel", 6),
++ GATE_PERI1(CLK_PERI_GCPU, "gcpu_ck", "gcpu_sel", 5),
++ GATE_PERI1(CLK_PERI_FHCTL, "fhctl_ck", "clk26m", 4),
++ GATE_PERI1(CLK_PERI_SPI1, "spi1_ck", "spi_sel", 3),
++ GATE_PERI1(CLK_PERI_AUXADC, "auxadc_ck", "clk26m", 2),
++ GATE_PERI1(CLK_PERI_PERI_PWRAP, "peri_pwrap_ck", "axi_sel", 1),
++ GATE_PERI1(CLK_PERI_I2C6, "i2c6_ck", "axi_sel", 0),
++};
++
++static const char * const uart_ck_sel_parents[] __initconst = {
++ "clk26m",
++ "uart_sel",
++};
++
++static const struct mtk_composite peri_clks[] __initconst = {
++ MUX(CLK_PERI_UART0_SEL, "uart0_ck_sel", uart_ck_sel_parents, 0x40c, 0, 1),
++ MUX(CLK_PERI_UART1_SEL, "uart1_ck_sel", uart_ck_sel_parents, 0x40c, 1, 1),
++ MUX(CLK_PERI_UART2_SEL, "uart2_ck_sel", uart_ck_sel_parents, 0x40c, 2, 1),
++ MUX(CLK_PERI_UART3_SEL, "uart3_ck_sel", uart_ck_sel_parents, 0x40c, 3, 1),
++};
++
++static void __init mtk_topckgen_init(struct device_node *node)
++{
++ struct clk_onecell_data *clk_data;
++ void __iomem *base;
++ int r;
++
++ base = of_iomap(node, 0);
++ if (!base) {
++ pr_err("%s(): ioremap failed\n", __func__);
++ return;
++ }
++
++ clk_data = mtk_alloc_clk_data(CLK_TOP_NR_CLK);
++
++ mtk_clk_register_factors(root_clk_alias, ARRAY_SIZE(root_clk_alias), clk_data);
++ mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs), clk_data);
++ mtk_clk_register_composites(top_muxes, ARRAY_SIZE(top_muxes), base,
++ &mt8135_clk_lock, clk_data);
++
++ clk_prepare_enable(clk_data->clks[CLK_TOP_CCI_SEL]);
++
++ r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
++ if (r)
++ pr_err("%s(): could not register clock provider: %d\n",
++ __func__, r);
++}
++CLK_OF_DECLARE(mtk_topckgen, "mediatek,mt8135-topckgen", mtk_topckgen_init);
++
++static void __init mtk_infrasys_init(struct device_node *node)
++{
++ struct clk_onecell_data *clk_data;
++ int r;
++
++ clk_data = mtk_alloc_clk_data(CLK_INFRA_NR_CLK);
++
++ mtk_clk_register_gates(node, infra_clks, ARRAY_SIZE(infra_clks),
++ clk_data);
++
++ clk_prepare_enable(clk_data->clks[CLK_INFRA_M4U]);
++
++ r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
++ if (r)
++ pr_err("%s(): could not register clock provider: %d\n",
++ __func__, r);
++
++ mtk_register_reset_controller(node, 2, 0x30);
++}
++CLK_OF_DECLARE(mtk_infrasys, "mediatek,mt8135-infracfg", mtk_infrasys_init);
++
++static void __init mtk_pericfg_init(struct device_node *node)
++{
++ struct clk_onecell_data *clk_data;
++ int r;
++ void __iomem *base;
++
++ base = of_iomap(node, 0);
++ if (!base) {
++ pr_err("%s(): ioremap failed\n", __func__);
++ return;
++ }
++
++ clk_data = mtk_alloc_clk_data(CLK_PERI_NR_CLK);
++
++ mtk_clk_register_gates(node, peri_gates, ARRAY_SIZE(peri_gates),
++ clk_data);
++ mtk_clk_register_composites(peri_clks, ARRAY_SIZE(peri_clks), base,
++ &mt8135_clk_lock, clk_data);
++
++ r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
++ if (r)
++ pr_err("%s(): could not register clock provider: %d\n",
++ __func__, r);
++
++ mtk_register_reset_controller(node, 2, 0);
++}
++CLK_OF_DECLARE(mtk_pericfg, "mediatek,mt8135-pericfg", mtk_pericfg_init);
++
++#define MT8135_PLL_FMAX (2000 * MHZ)
++#define CON0_MT8135_RST_BAR BIT(27)
++
++#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, _pcw_shift) { \
++ .id = _id, \
++ .name = _name, \
++ .reg = _reg, \
++ .pwr_reg = _pwr_reg, \
++ .en_mask = _en_mask, \
++ .flags = _flags, \
++ .rst_bar_mask = CON0_MT8135_RST_BAR, \
++ .fmax = MT8135_PLL_FMAX, \
++ .pcwbits = _pcwbits, \
++ .pd_reg = _pd_reg, \
++ .pd_shift = _pd_shift, \
++ .tuner_reg = _tuner_reg, \
++ .pcw_reg = _pcw_reg, \
++ .pcw_shift = _pcw_shift, \
++ }
++
++static const struct mtk_pll_data plls[] = {
++ PLL(CLK_APMIXED_ARMPLL1, "armpll1", 0x200, 0x218, 0x80000001, 0, 21, 0x204, 24, 0x0, 0x204, 0),
++ PLL(CLK_APMIXED_ARMPLL2, "armpll2", 0x2cc, 0x2e4, 0x80000001, 0, 21, 0x2d0, 24, 0x0, 0x2d0, 0),
++ PLL(CLK_APMIXED_MAINPLL, "mainpll", 0x21c, 0x234, 0xf0000001, HAVE_RST_BAR, 21, 0x21c, 6, 0x0, 0x220, 0),
++ PLL(CLK_APMIXED_UNIVPLL, "univpll", 0x238, 0x250, 0xf3000001, HAVE_RST_BAR, 7, 0x238, 6, 0x0, 0x238, 9),
++ PLL(CLK_APMIXED_MMPLL, "mmpll", 0x254, 0x26c, 0xf0000001, HAVE_RST_BAR, 21, 0x254, 6, 0x0, 0x258, 0),
++ PLL(CLK_APMIXED_MSDCPLL, "msdcpll", 0x278, 0x290, 0x80000001, 0, 21, 0x278, 6, 0x0, 0x27c, 0),
++ PLL(CLK_APMIXED_TVDPLL, "tvdpll", 0x294, 0x2ac, 0x80000001, 0, 31, 0x294, 6, 0x0, 0x298, 0),
++ PLL(CLK_APMIXED_LVDSPLL, "lvdspll", 0x2b0, 0x2c8, 0x80000001, 0, 21, 0x2b0, 6, 0x0, 0x2b4, 0),
++ PLL(CLK_APMIXED_AUDPLL, "audpll", 0x2e8, 0x300, 0x80000001, 0, 31, 0x2e8, 6, 0x2f8, 0x2ec, 0),
++ PLL(CLK_APMIXED_VDECPLL, "vdecpll", 0x304, 0x31c, 0x80000001, 0, 21, 0x2b0, 6, 0x0, 0x308, 0),
++};
++
++static void __init mtk_apmixedsys_init(struct device_node *node)
++{
++ struct clk_onecell_data *clk_data;
++
++ clk_data = mtk_alloc_clk_data(ARRAY_SIZE(plls));
++ if (!clk_data)
++ return;
++
++ mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data);
++}
++CLK_OF_DECLARE(mtk_apmixedsys, "mediatek,mt8135-apmixedsys",
++ mtk_apmixedsys_init);
+diff --git a/include/dt-bindings/clock/mt8135-clk.h b/include/dt-bindings/clock/mt8135-clk.h
+new file mode 100644
+index 0000000..6dac6c0
+--- /dev/null
++++ b/include/dt-bindings/clock/mt8135-clk.h
+@@ -0,0 +1,194 @@
++/*
++ * Copyright (c) 2014 MediaTek Inc.
++ * Author: James Liao <jamesjj.liao@mediatek.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#ifndef _DT_BINDINGS_CLK_MT8135_H
++#define _DT_BINDINGS_CLK_MT8135_H
++
++/* TOPCKGEN */
++
++#define CLK_TOP_DSI0_LNTC_DSICLK 1
++#define CLK_TOP_HDMITX_CLKDIG_CTS 2
++#define CLK_TOP_CLKPH_MCK 3
++#define CLK_TOP_CPUM_TCK_IN 4
++#define CLK_TOP_MAINPLL_806M 5
++#define CLK_TOP_MAINPLL_537P3M 6
++#define CLK_TOP_MAINPLL_322P4M 7
++#define CLK_TOP_MAINPLL_230P3M 8
++#define CLK_TOP_UNIVPLL_624M 9
++#define CLK_TOP_UNIVPLL_416M 10
++#define CLK_TOP_UNIVPLL_249P6M 11
++#define CLK_TOP_UNIVPLL_178P3M 12
++#define CLK_TOP_UNIVPLL_48M 13
++#define CLK_TOP_MMPLL_D2 14
++#define CLK_TOP_MMPLL_D3 15
++#define CLK_TOP_MMPLL_D5 16
++#define CLK_TOP_MMPLL_D7 17
++#define CLK_TOP_MMPLL_D4 18
++#define CLK_TOP_MMPLL_D6 19
++#define CLK_TOP_SYSPLL_D2 20
++#define CLK_TOP_SYSPLL_D4 21
++#define CLK_TOP_SYSPLL_D6 22
++#define CLK_TOP_SYSPLL_D8 23
++#define CLK_TOP_SYSPLL_D10 24
++#define CLK_TOP_SYSPLL_D12 25
++#define CLK_TOP_SYSPLL_D16 26
++#define CLK_TOP_SYSPLL_D24 27
++#define CLK_TOP_SYSPLL_D3 28
++#define CLK_TOP_SYSPLL_D2P5 29
++#define CLK_TOP_SYSPLL_D5 30
++#define CLK_TOP_SYSPLL_D3P5 31
++#define CLK_TOP_UNIVPLL1_D2 32
++#define CLK_TOP_UNIVPLL1_D4 33
++#define CLK_TOP_UNIVPLL1_D6 34
++#define CLK_TOP_UNIVPLL1_D8 35
++#define CLK_TOP_UNIVPLL1_D10 36
++#define CLK_TOP_UNIVPLL2_D2 37
++#define CLK_TOP_UNIVPLL2_D4 38
++#define CLK_TOP_UNIVPLL2_D6 39
++#define CLK_TOP_UNIVPLL2_D8 40
++#define CLK_TOP_UNIVPLL_D3 41
++#define CLK_TOP_UNIVPLL_D5 42
++#define CLK_TOP_UNIVPLL_D7 43
++#define CLK_TOP_UNIVPLL_D10 44
++#define CLK_TOP_UNIVPLL_D26 45
++#define CLK_TOP_APLL 46
++#define CLK_TOP_APLL_D4 47
++#define CLK_TOP_APLL_D8 48
++#define CLK_TOP_APLL_D16 49
++#define CLK_TOP_APLL_D24 50
++#define CLK_TOP_LVDSPLL_D2 51
++#define CLK_TOP_LVDSPLL_D4 52
++#define CLK_TOP_LVDSPLL_D8 53
++#define CLK_TOP_LVDSTX_CLKDIG_CT 54
++#define CLK_TOP_VPLL_DPIX 55
++#define CLK_TOP_TVHDMI_H 56
++#define CLK_TOP_HDMITX_CLKDIG_D2 57
++#define CLK_TOP_HDMITX_CLKDIG_D3 58
++#define CLK_TOP_TVHDMI_D2 59
++#define CLK_TOP_TVHDMI_D4 60
++#define CLK_TOP_MEMPLL_MCK_D4 61
++#define CLK_TOP_AXI_SEL 62
++#define CLK_TOP_SMI_SEL 63
++#define CLK_TOP_MFG_SEL 64
++#define CLK_TOP_IRDA_SEL 65
++#define CLK_TOP_CAM_SEL 66
++#define CLK_TOP_AUD_INTBUS_SEL 67
++#define CLK_TOP_JPG_SEL 68
++#define CLK_TOP_DISP_SEL 69
++#define CLK_TOP_MSDC30_1_SEL 70
++#define CLK_TOP_MSDC30_2_SEL 71
++#define CLK_TOP_MSDC30_3_SEL 72
++#define CLK_TOP_MSDC30_4_SEL 73
++#define CLK_TOP_USB20_SEL 74
++#define CLK_TOP_VENC_SEL 75
++#define CLK_TOP_SPI_SEL 76
++#define CLK_TOP_UART_SEL 77
++#define CLK_TOP_MEM_SEL 78
++#define CLK_TOP_CAMTG_SEL 79
++#define CLK_TOP_AUDIO_SEL 80
++#define CLK_TOP_FIX_SEL 81
++#define CLK_TOP_VDEC_SEL 82
++#define CLK_TOP_DDRPHYCFG_SEL 83
++#define CLK_TOP_DPILVDS_SEL 84
++#define CLK_TOP_PMICSPI_SEL 85
++#define CLK_TOP_MSDC30_0_SEL 86
++#define CLK_TOP_SMI_MFG_AS_SEL 87
++#define CLK_TOP_GCPU_SEL 88
++#define CLK_TOP_DPI1_SEL 89
++#define CLK_TOP_CCI_SEL 90
++#define CLK_TOP_APLL_SEL 91
++#define CLK_TOP_HDMIPLL_SEL 92
++#define CLK_TOP_NR_CLK 93
++
++/* APMIXED_SYS */
++
++#define CLK_APMIXED_ARMPLL1 1
++#define CLK_APMIXED_ARMPLL2 2
++#define CLK_APMIXED_MAINPLL 3
++#define CLK_APMIXED_UNIVPLL 4
++#define CLK_APMIXED_MMPLL 5
++#define CLK_APMIXED_MSDCPLL 6
++#define CLK_APMIXED_TVDPLL 7
++#define CLK_APMIXED_LVDSPLL 8
++#define CLK_APMIXED_AUDPLL 9
++#define CLK_APMIXED_VDECPLL 10
++#define CLK_APMIXED_NR_CLK 11
++
++/* INFRA_SYS */
++
++#define CLK_INFRA_PMIC_WRAP 1
++#define CLK_INFRA_PMICSPI 2
++#define CLK_INFRA_CCIF1_AP_CTRL 3
++#define CLK_INFRA_CCIF0_AP_CTRL 4
++#define CLK_INFRA_KP 5
++#define CLK_INFRA_CPUM 6
++#define CLK_INFRA_M4U 7
++#define CLK_INFRA_MFGAXI 8
++#define CLK_INFRA_DEVAPC 9
++#define CLK_INFRA_AUDIO 10
++#define CLK_INFRA_MFG_BUS 11
++#define CLK_INFRA_SMI 12
++#define CLK_INFRA_DBGCLK 13
++#define CLK_INFRA_NR_CLK 14
++
++/* PERI_SYS */
++
++#define CLK_PERI_I2C5 1
++#define CLK_PERI_I2C4 2
++#define CLK_PERI_I2C3 3
++#define CLK_PERI_I2C2 4
++#define CLK_PERI_I2C1 5
++#define CLK_PERI_I2C0 6
++#define CLK_PERI_UART3 7
++#define CLK_PERI_UART2 8
++#define CLK_PERI_UART1 9
++#define CLK_PERI_UART0 10
++#define CLK_PERI_IRDA 11
++#define CLK_PERI_NLI 12
++#define CLK_PERI_MD_HIF 13
++#define CLK_PERI_AP_HIF 14
++#define CLK_PERI_MSDC30_3 15
++#define CLK_PERI_MSDC30_2 16
++#define CLK_PERI_MSDC30_1 17
++#define CLK_PERI_MSDC20_2 18
++#define CLK_PERI_MSDC20_1 19
++#define CLK_PERI_AP_DMA 20
++#define CLK_PERI_USB1 21
++#define CLK_PERI_USB0 22
++#define CLK_PERI_PWM 23
++#define CLK_PERI_PWM7 24
++#define CLK_PERI_PWM6 25
++#define CLK_PERI_PWM5 26
++#define CLK_PERI_PWM4 27
++#define CLK_PERI_PWM3 28
++#define CLK_PERI_PWM2 29
++#define CLK_PERI_PWM1 30
++#define CLK_PERI_THERM 31
++#define CLK_PERI_NFI 32
++#define CLK_PERI_USBSLV 33
++#define CLK_PERI_USB1_MCU 34
++#define CLK_PERI_USB0_MCU 35
++#define CLK_PERI_GCPU 36
++#define CLK_PERI_FHCTL 37
++#define CLK_PERI_SPI1 38
++#define CLK_PERI_AUXADC 39
++#define CLK_PERI_PERI_PWRAP 40
++#define CLK_PERI_I2C6 41
++#define CLK_PERI_UART0_SEL 42
++#define CLK_PERI_UART1_SEL 43
++#define CLK_PERI_UART2_SEL 44
++#define CLK_PERI_UART3_SEL 45
++#define CLK_PERI_NR_CLK 46
++
++#endif /* _DT_BINDINGS_CLK_MT8135_H */
+diff --git a/include/dt-bindings/reset-controller/mt8135-resets.h b/include/dt-bindings/reset-controller/mt8135-resets.h
+new file mode 100644
+index 0000000..1fb6295
+--- /dev/null
++++ b/include/dt-bindings/reset-controller/mt8135-resets.h
+@@ -0,0 +1,64 @@
++/*
++ * Copyright (c) 2014 MediaTek Inc.
++ * Author: Flora Fu, MediaTek
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#ifndef _DT_BINDINGS_RESET_CONTROLLER_MT8135
++#define _DT_BINDINGS_RESET_CONTROLLER_MT8135
++
++/* INFRACFG resets */
++#define MT8135_INFRA_EMI_REG_RST 0
++#define MT8135_INFRA_DRAMC0_A0_RST 1
++#define MT8135_INFRA_CCIF0_RST 2
++#define MT8135_INFRA_APCIRQ_EINT_RST 3
++#define MT8135_INFRA_APXGPT_RST 4
++#define MT8135_INFRA_SCPSYS_RST 5
++#define MT8135_INFRA_CCIF1_RST 6
++#define MT8135_INFRA_PMIC_WRAP_RST 7
++#define MT8135_INFRA_KP_RST 8
++#define MT8135_INFRA_EMI_RST 32
++#define MT8135_INFRA_DRAMC0_RST 34
++#define MT8135_INFRA_SMI_RST 35
++#define MT8135_INFRA_M4U_RST 36
++
++/* PERICFG resets */
++#define MT8135_PERI_UART0_SW_RST 0
++#define MT8135_PERI_UART1_SW_RST 1
++#define MT8135_PERI_UART2_SW_RST 2
++#define MT8135_PERI_UART3_SW_RST 3
++#define MT8135_PERI_IRDA_SW_RST 4
++#define MT8135_PERI_PTP_SW_RST 5
++#define MT8135_PERI_AP_HIF_SW_RST 6
++#define MT8135_PERI_GPCU_SW_RST 7
++#define MT8135_PERI_MD_HIF_SW_RST 8
++#define MT8135_PERI_NLI_SW_RST 9
++#define MT8135_PERI_AUXADC_SW_RST 10
++#define MT8135_PERI_DMA_SW_RST 11
++#define MT8135_PERI_NFI_SW_RST 14
++#define MT8135_PERI_PWM_SW_RST 15
++#define MT8135_PERI_THERM_SW_RST 16
++#define MT8135_PERI_MSDC0_SW_RST 17
++#define MT8135_PERI_MSDC1_SW_RST 18
++#define MT8135_PERI_MSDC2_SW_RST 19
++#define MT8135_PERI_MSDC3_SW_RST 20
++#define MT8135_PERI_I2C0_SW_RST 22
++#define MT8135_PERI_I2C1_SW_RST 23
++#define MT8135_PERI_I2C2_SW_RST 24
++#define MT8135_PERI_I2C3_SW_RST 25
++#define MT8135_PERI_I2C4_SW_RST 26
++#define MT8135_PERI_I2C5_SW_RST 27
++#define MT8135_PERI_I2C6_SW_RST 28
++#define MT8135_PERI_USB_SW_RST 29
++#define MT8135_PERI_SPI1_SW_RST 33
++#define MT8135_PERI_PWRAP_BRIDGE_SW_RST 34
++
++#endif /* _DT_BINDINGS_RESET_CONTROLLER_MT8135 */
+--
+1.7.10.4
+
--- /dev/null
+From 0efcd47787019284a334186fce134ee475c79211 Mon Sep 17 00:00:00 2001
+From: James Liao <jamesjj.liao@mediatek.com>
+Date: Thu, 23 Apr 2015 10:35:42 +0200
+Subject: [PATCH 05/76] clk: mediatek: Add basic clocks for Mediatek MT8173.
+
+This patch adds basic clocks for MT8173, including TOPCKGEN, PLLs,
+INFRA and PERI clocks.
+
+Signed-off-by: James Liao <jamesjj.liao@mediatek.com>
+Signed-off-by: Henry Chen <henryc.chen@mediatek.com>
+Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
+---
+ drivers/clk/mediatek/Makefile | 1 +
+ drivers/clk/mediatek/clk-mt8173.c | 830 ++++++++++++++++++++
+ include/dt-bindings/clock/mt8173-clk.h | 235 ++++++
+ .../dt-bindings/reset-controller/mt8173-resets.h | 63 ++
+ 4 files changed, 1129 insertions(+)
+ create mode 100644 drivers/clk/mediatek/clk-mt8173.c
+ create mode 100644 include/dt-bindings/clock/mt8173-clk.h
+ create mode 100644 include/dt-bindings/reset-controller/mt8173-resets.h
+
+diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile
+index 12ce576..8e4b2a4 100644
+--- a/drivers/clk/mediatek/Makefile
++++ b/drivers/clk/mediatek/Makefile
+@@ -1,3 +1,4 @@
+ obj-y += clk-mtk.o clk-pll.o clk-gate.o
+ obj-$(CONFIG_RESET_CONTROLLER) += reset.o
+ obj-y += clk-mt8135.o
++obj-y += clk-mt8173.o
+diff --git a/drivers/clk/mediatek/clk-mt8173.c b/drivers/clk/mediatek/clk-mt8173.c
+new file mode 100644
+index 0000000..357b080
+--- /dev/null
++++ b/drivers/clk/mediatek/clk-mt8173.c
+@@ -0,0 +1,830 @@
++/*
++ * Copyright (c) 2014 MediaTek Inc.
++ * Author: James Liao <jamesjj.liao@mediatek.com>
++ *
++ * 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.
++ */
++
++#include <linux/of.h>
++#include <linux/of_address.h>
++#include <linux/slab.h>
++#include <linux/mfd/syscon.h>
++
++#include "clk-mtk.h"
++#include "clk-gate.h"
++
++#include <dt-bindings/clock/mt8173-clk.h>
++
++static DEFINE_SPINLOCK(mt8173_clk_lock);
++
++static const struct mtk_fixed_factor root_clk_alias[] __initconst = {
++ FACTOR(CLK_TOP_CLKPH_MCK_O, "clkph_mck_o", "clk_null", 1, 1),
++ FACTOR(CLK_TOP_DPI, "dpi_ck", "clk_null", 1, 1),
++ FACTOR(CLK_TOP_USB_SYSPLL_125M, "usb_syspll_125m", "clk_null", 1, 1),
++ FACTOR(CLK_TOP_HDMITX_DIG_CTS, "hdmitx_dig_cts", "clk_null", 1, 1),
++};
++
++static const struct mtk_fixed_factor top_divs[] __initconst = {
++ FACTOR(CLK_TOP_ARMCA7PLL_754M, "armca7pll_754m", "armca7pll", 1, 2),
++ FACTOR(CLK_TOP_ARMCA7PLL_502M, "armca7pll_502m", "armca7pll", 1, 3),
++
++ FACTOR(CLK_TOP_MAIN_H546M, "main_h546m", "mainpll", 1, 2),
++ FACTOR(CLK_TOP_MAIN_H364M, "main_h364m", "mainpll", 1, 3),
++ FACTOR(CLK_TOP_MAIN_H218P4M, "main_h218p4m", "mainpll", 1, 5),
++ FACTOR(CLK_TOP_MAIN_H156M, "main_h156m", "mainpll", 1, 7),
++
++ FACTOR(CLK_TOP_TVDPLL_445P5M, "tvdpll_445p5m", "tvdpll", 1, 4),
++ FACTOR(CLK_TOP_TVDPLL_594M, "tvdpll_594m", "tvdpll", 1, 3),
++
++ FACTOR(CLK_TOP_UNIV_624M, "univ_624m", "univpll", 1, 2),
++ FACTOR(CLK_TOP_UNIV_416M, "univ_416m", "univpll", 1, 3),
++ FACTOR(CLK_TOP_UNIV_249P6M, "univ_249p6m", "univpll", 1, 5),
++ FACTOR(CLK_TOP_UNIV_178P3M, "univ_178p3m", "univpll", 1, 7),
++ FACTOR(CLK_TOP_UNIV_48M, "univ_48m", "univpll", 1, 26),
++
++ FACTOR(CLK_TOP_CLKRTC_EXT, "clkrtc_ext", "clk32k", 1, 1),
++ FACTOR(CLK_TOP_CLKRTC_INT, "clkrtc_int", "clk26m", 1, 793),
++ FACTOR(CLK_TOP_FPC, "fpc_ck", "clk26m", 1, 1),
++
++ FACTOR(CLK_TOP_HDMITXPLL_D2, "hdmitxpll_d2", "hdmitx_dig_cts", 1, 2),
++ FACTOR(CLK_TOP_HDMITXPLL_D3, "hdmitxpll_d3", "hdmitx_dig_cts", 1, 3),
++
++ FACTOR(CLK_TOP_ARMCA7PLL_D2, "armca7pll_d2", "armca7pll_754m", 1, 1),
++ FACTOR(CLK_TOP_ARMCA7PLL_D3, "armca7pll_d3", "armca7pll_502m", 1, 1),
++
++ FACTOR(CLK_TOP_APLL1, "apll1_ck", "apll1", 1, 1),
++ FACTOR(CLK_TOP_APLL2, "apll2_ck", "apll2", 1, 1),
++
++ FACTOR(CLK_TOP_DMPLL, "dmpll_ck", "clkph_mck_o", 1, 1),
++ FACTOR(CLK_TOP_DMPLL_D2, "dmpll_d2", "clkph_mck_o", 1, 2),
++ FACTOR(CLK_TOP_DMPLL_D4, "dmpll_d4", "clkph_mck_o", 1, 4),
++ FACTOR(CLK_TOP_DMPLL_D8, "dmpll_d8", "clkph_mck_o", 1, 8),
++ FACTOR(CLK_TOP_DMPLL_D16, "dmpll_d16", "clkph_mck_o", 1, 16),
++
++ FACTOR(CLK_TOP_LVDSPLL_D2, "lvdspll_d2", "lvdspll", 1, 2),
++ FACTOR(CLK_TOP_LVDSPLL_D4, "lvdspll_d4", "lvdspll", 1, 4),
++ FACTOR(CLK_TOP_LVDSPLL_D8, "lvdspll_d8", "lvdspll", 1, 8),
++
++ FACTOR(CLK_TOP_MMPLL, "mmpll_ck", "mmpll", 1, 1),
++ FACTOR(CLK_TOP_MMPLL_D2, "mmpll_d2", "mmpll", 1, 2),
++
++ FACTOR(CLK_TOP_MSDCPLL, "msdcpll_ck", "msdcpll", 1, 1),
++ FACTOR(CLK_TOP_MSDCPLL_D2, "msdcpll_d2", "msdcpll", 1, 2),
++ FACTOR(CLK_TOP_MSDCPLL_D4, "msdcpll_d4", "msdcpll", 1, 4),
++ FACTOR(CLK_TOP_MSDCPLL2, "msdcpll2_ck", "msdcpll2", 1, 1),
++ FACTOR(CLK_TOP_MSDCPLL2_D2, "msdcpll2_d2", "msdcpll2", 1, 2),
++ FACTOR(CLK_TOP_MSDCPLL2_D4, "msdcpll2_d4", "msdcpll2", 1, 4),
++
++ FACTOR(CLK_TOP_SYSPLL_D2, "syspll_d2", "main_h546m", 1, 1),
++ FACTOR(CLK_TOP_SYSPLL1_D2, "syspll1_d2", "main_h546m", 1, 2),
++ FACTOR(CLK_TOP_SYSPLL1_D4, "syspll1_d4", "main_h546m", 1, 4),
++ FACTOR(CLK_TOP_SYSPLL1_D8, "syspll1_d8", "main_h546m", 1, 8),
++ FACTOR(CLK_TOP_SYSPLL1_D16, "syspll1_d16", "main_h546m", 1, 16),
++ FACTOR(CLK_TOP_SYSPLL_D3, "syspll_d3", "main_h364m", 1, 1),
++ FACTOR(CLK_TOP_SYSPLL2_D2, "syspll2_d2", "main_h364m", 1, 2),
++ FACTOR(CLK_TOP_SYSPLL2_D4, "syspll2_d4", "main_h364m", 1, 4),
++ FACTOR(CLK_TOP_SYSPLL_D5, "syspll_d5", "main_h218p4m", 1, 1),
++ FACTOR(CLK_TOP_SYSPLL3_D2, "syspll3_d2", "main_h218p4m", 1, 2),
++ FACTOR(CLK_TOP_SYSPLL3_D4, "syspll3_d4", "main_h218p4m", 1, 4),
++ FACTOR(CLK_TOP_SYSPLL_D7, "syspll_d7", "main_h156m", 1, 1),
++ FACTOR(CLK_TOP_SYSPLL4_D2, "syspll4_d2", "main_h156m", 1, 2),
++ FACTOR(CLK_TOP_SYSPLL4_D4, "syspll4_d4", "main_h156m", 1, 4),
++
++ FACTOR(CLK_TOP_TVDPLL, "tvdpll_ck", "tvdpll_594m", 1, 1),
++ FACTOR(CLK_TOP_TVDPLL_D2, "tvdpll_d2", "tvdpll_594m", 1, 2),
++ FACTOR(CLK_TOP_TVDPLL_D4, "tvdpll_d4", "tvdpll_594m", 1, 4),
++ FACTOR(CLK_TOP_TVDPLL_D8, "tvdpll_d8", "tvdpll_594m", 1, 8),
++ FACTOR(CLK_TOP_TVDPLL_D16, "tvdpll_d16", "tvdpll_594m", 1, 16),
++
++ FACTOR(CLK_TOP_UNIVPLL_D2, "univpll_d2", "univ_624m", 1, 1),
++ FACTOR(CLK_TOP_UNIVPLL1_D2, "univpll1_d2", "univ_624m", 1, 2),
++ FACTOR(CLK_TOP_UNIVPLL1_D4, "univpll1_d4", "univ_624m", 1, 4),
++ FACTOR(CLK_TOP_UNIVPLL1_D8, "univpll1_d8", "univ_624m", 1, 8),
++ FACTOR(CLK_TOP_UNIVPLL_D3, "univpll_d3", "univ_416m", 1, 1),
++ FACTOR(CLK_TOP_UNIVPLL2_D2, "univpll2_d2", "univ_416m", 1, 2),
++ FACTOR(CLK_TOP_UNIVPLL2_D4, "univpll2_d4", "univ_416m", 1, 4),
++ FACTOR(CLK_TOP_UNIVPLL2_D8, "univpll2_d8", "univ_416m", 1, 8),
++ FACTOR(CLK_TOP_UNIVPLL_D5, "univpll_d5", "univ_249p6m", 1, 1),
++ FACTOR(CLK_TOP_UNIVPLL3_D2, "univpll3_d2", "univ_249p6m", 1, 2),
++ FACTOR(CLK_TOP_UNIVPLL3_D4, "univpll3_d4", "univ_249p6m", 1, 4),
++ FACTOR(CLK_TOP_UNIVPLL3_D8, "univpll3_d8", "univ_249p6m", 1, 8),
++ FACTOR(CLK_TOP_UNIVPLL_D7, "univpll_d7", "univ_178p3m", 1, 1),
++ FACTOR(CLK_TOP_UNIVPLL_D26, "univpll_d26", "univ_48m", 1, 1),
++ FACTOR(CLK_TOP_UNIVPLL_D52, "univpll_d52", "univ_48m", 1, 2),
++
++ FACTOR(CLK_TOP_VCODECPLL, "vcodecpll_ck", "vcodecpll", 1, 3),
++ FACTOR(CLK_TOP_VCODECPLL_370P5, "vcodecpll_370p5", "vcodecpll", 1, 4),
++
++ FACTOR(CLK_TOP_VENCPLL, "vencpll_ck", "vencpll", 1, 1),
++ FACTOR(CLK_TOP_VENCPLL_D2, "vencpll_d2", "vencpll", 1, 2),
++ FACTOR(CLK_TOP_VENCPLL_D4, "vencpll_d4", "vencpll", 1, 4),
++};
++
++static const char * const axi_parents[] __initconst = {
++ "clk26m",
++ "syspll1_d2",
++ "syspll_d5",
++ "syspll1_d4",
++ "univpll_d5",
++ "univpll2_d2",
++ "dmpll_d2",
++ "dmpll_d4"
++};
++
++static const char * const mem_parents[] __initconst = {
++ "clk26m",
++ "dmpll_ck"
++};
++
++static const char * const ddrphycfg_parents[] __initconst = {
++ "clk26m",
++ "syspll1_d8"
++};
++
++static const char * const mm_parents[] __initconst = {
++ "clk26m",
++ "vencpll_d2",
++ "main_h364m",
++ "syspll1_d2",
++ "syspll_d5",
++ "syspll1_d4",
++ "univpll1_d2",
++ "univpll2_d2",
++ "dmpll_d2"
++};
++
++static const char * const pwm_parents[] __initconst = {
++ "clk26m",
++ "univpll2_d4",
++ "univpll3_d2",
++ "univpll1_d4"
++};
++
++static const char * const vdec_parents[] __initconst = {
++ "clk26m",
++ "vcodecpll_ck",
++ "tvdpll_445p5m",
++ "univpll_d3",
++ "vencpll_d2",
++ "syspll_d3",
++ "univpll1_d2",
++ "mmpll_d2",
++ "dmpll_d2",
++ "dmpll_d4"
++};
++
++static const char * const venc_parents[] __initconst = {
++ "clk26m",
++ "vcodecpll_ck",
++ "tvdpll_445p5m",
++ "univpll_d3",
++ "vencpll_d2",
++ "syspll_d3",
++ "univpll1_d2",
++ "univpll2_d2",
++ "dmpll_d2",
++ "dmpll_d4"
++};
++
++static const char * const mfg_parents[] __initconst = {
++ "clk26m",
++ "mmpll_ck",
++ "dmpll_ck",
++ "clk26m",
++ "clk26m",
++ "clk26m",
++ "clk26m",
++ "clk26m",
++ "clk26m",
++ "syspll_d3",
++ "syspll1_d2",
++ "syspll_d5",
++ "univpll_d3",
++ "univpll1_d2",
++ "univpll_d5",
++ "univpll2_d2"
++};
++
++static const char * const camtg_parents[] __initconst = {
++ "clk26m",
++ "univpll_d26",
++ "univpll2_d2",
++ "syspll3_d2",
++ "syspll3_d4",
++ "univpll1_d4"
++};
++
++static const char * const uart_parents[] __initconst = {
++ "clk26m",
++ "univpll2_d8"
++};
++
++static const char * const spi_parents[] __initconst = {
++ "clk26m",
++ "syspll3_d2",
++ "syspll1_d4",
++ "syspll4_d2",
++ "univpll3_d2",
++ "univpll2_d4",
++ "univpll1_d8"
++};
++
++static const char * const usb20_parents[] __initconst = {
++ "clk26m",
++ "univpll1_d8",
++ "univpll3_d4"
++};
++
++static const char * const usb30_parents[] __initconst = {
++ "clk26m",
++ "univpll3_d2",
++ "usb_syspll_125m",
++ "univpll2_d4"
++};
++
++static const char * const msdc50_0_h_parents[] __initconst = {
++ "clk26m",
++ "syspll1_d2",
++ "syspll2_d2",
++ "syspll4_d2",
++ "univpll_d5",
++ "univpll1_d4"
++};
++
++static const char * const msdc50_0_parents[] __initconst = {
++ "clk26m",
++ "msdcpll_ck",
++ "msdcpll_d2",
++ "univpll1_d4",
++ "syspll2_d2",
++ "syspll_d7",
++ "msdcpll_d4",
++ "vencpll_d4",
++ "tvdpll_ck",
++ "univpll_d2",
++ "univpll1_d2",
++ "mmpll_ck",
++ "msdcpll2_ck",
++ "msdcpll2_d2",
++ "msdcpll2_d4"
++};
++
++static const char * const msdc30_1_parents[] __initconst = {
++ "clk26m",
++ "univpll2_d2",
++ "msdcpll_d4",
++ "univpll1_d4",
++ "syspll2_d2",
++ "syspll_d7",
++ "univpll_d7",
++ "vencpll_d4"
++};
++
++static const char * const msdc30_2_parents[] __initconst = {
++ "clk26m",
++ "univpll2_d2",
++ "msdcpll_d4",
++ "univpll1_d4",
++ "syspll2_d2",
++ "syspll_d7",
++ "univpll_d7",
++ "vencpll_d2"
++};
++
++static const char * const msdc30_3_parents[] __initconst = {
++ "clk26m",
++ "msdcpll2_ck",
++ "msdcpll2_d2",
++ "univpll2_d2",
++ "msdcpll2_d4",
++ "msdcpll_d4",
++ "univpll1_d4",
++ "syspll2_d2",
++ "syspll_d7",
++ "univpll_d7",
++ "vencpll_d4",
++ "msdcpll_ck",
++ "msdcpll_d2",
++ "msdcpll_d4"
++};
++
++static const char * const audio_parents[] __initconst = {
++ "clk26m",
++ "syspll3_d4",
++ "syspll4_d4",
++ "syspll1_d16"
++};
++
++static const char * const aud_intbus_parents[] __initconst = {
++ "clk26m",
++ "syspll1_d4",
++ "syspll4_d2",
++ "univpll3_d2",
++ "univpll2_d8",
++ "dmpll_d4",
++ "dmpll_d8"
++};
++
++static const char * const pmicspi_parents[] __initconst = {
++ "clk26m",
++ "syspll1_d8",
++ "syspll3_d4",
++ "syspll1_d16",
++ "univpll3_d4",
++ "univpll_d26",
++ "dmpll_d8",
++ "dmpll_d16"
++};
++
++static const char * const scp_parents[] __initconst = {
++ "clk26m",
++ "syspll1_d2",
++ "univpll_d5",
++ "syspll_d5",
++ "dmpll_d2",
++ "dmpll_d4"
++};
++
++static const char * const atb_parents[] __initconst = {
++ "clk26m",
++ "syspll1_d2",
++ "univpll_d5",
++ "dmpll_d2"
++};
++
++static const char * const venc_lt_parents[] __initconst = {
++ "clk26m",
++ "univpll_d3",
++ "vcodecpll_ck",
++ "tvdpll_445p5m",
++ "vencpll_d2",
++ "syspll_d3",
++ "univpll1_d2",
++ "univpll2_d2",
++ "syspll1_d2",
++ "univpll_d5",
++ "vcodecpll_370p5",
++ "dmpll_ck"
++};
++
++static const char * const dpi0_parents[] __initconst = {
++ "clk26m",
++ "tvdpll_d2",
++ "tvdpll_d4",
++ "clk26m",
++ "clk26m",
++ "tvdpll_d8",
++ "tvdpll_d16"
++};
++
++static const char * const irda_parents[] __initconst = {
++ "clk26m",
++ "univpll2_d4",
++ "syspll2_d4"
++};
++
++static const char * const cci400_parents[] __initconst = {
++ "clk26m",
++ "vencpll_ck",
++ "armca7pll_754m",
++ "armca7pll_502m",
++ "univpll_d2",
++ "syspll_d2",
++ "msdcpll_ck",
++ "dmpll_ck"
++};
++
++static const char * const aud_1_parents[] __initconst = {
++ "clk26m",
++ "apll1_ck",
++ "univpll2_d4",
++ "univpll2_d8"
++};
++
++static const char * const aud_2_parents[] __initconst = {
++ "clk26m",
++ "apll2_ck",
++ "univpll2_d4",
++ "univpll2_d8"
++};
++
++static const char * const mem_mfg_in_parents[] __initconst = {
++ "clk26m",
++ "mmpll_ck",
++ "dmpll_ck",
++ "clk26m"
++};
++
++static const char * const axi_mfg_in_parents[] __initconst = {
++ "clk26m",
++ "axi_sel",
++ "dmpll_d2"
++};
++
++static const char * const scam_parents[] __initconst = {
++ "clk26m",
++ "syspll3_d2",
++ "univpll2_d4",
++ "dmpll_d4"
++};
++
++static const char * const spinfi_ifr_parents[] __initconst = {
++ "clk26m",
++ "univpll2_d8",
++ "univpll3_d4",
++ "syspll4_d2",
++ "univpll2_d4",
++ "univpll3_d2",
++ "syspll1_d4",
++ "univpll1_d4"
++};
++
++static const char * const hdmi_parents[] __initconst = {
++ "clk26m",
++ "hdmitx_dig_cts",
++ "hdmitxpll_d2",
++ "hdmitxpll_d3"
++};
++
++static const char * const dpilvds_parents[] __initconst = {
++ "clk26m",
++ "lvdspll",
++ "lvdspll_d2",
++ "lvdspll_d4",
++ "lvdspll_d8",
++ "fpc_ck"
++};
++
++static const char * const msdc50_2_h_parents[] __initconst = {
++ "clk26m",
++ "syspll1_d2",
++ "syspll2_d2",
++ "syspll4_d2",
++ "univpll_d5",
++ "univpll1_d4"
++};
++
++static const char * const hdcp_parents[] __initconst = {
++ "clk26m",
++ "syspll4_d2",
++ "syspll3_d4",
++ "univpll2_d4"
++};
++
++static const char * const hdcp_24m_parents[] __initconst = {
++ "clk26m",
++ "univpll_d26",
++ "univpll_d52",
++ "univpll2_d8"
++};
++
++static const char * const rtc_parents[] __initconst = {
++ "clkrtc_int",
++ "clkrtc_ext",
++ "clk26m",
++ "univpll3_d8"
++};
++
++static const char * const i2s0_m_ck_parents[] __initconst = {
++ "apll1_div1",
++ "apll2_div1"
++};
++
++static const char * const i2s1_m_ck_parents[] __initconst = {
++ "apll1_div2",
++ "apll2_div2"
++};
++
++static const char * const i2s2_m_ck_parents[] __initconst = {
++ "apll1_div3",
++ "apll2_div3"
++};
++
++static const char * const i2s3_m_ck_parents[] __initconst = {
++ "apll1_div4",
++ "apll2_div4"
++};
++
++static const char * const i2s3_b_ck_parents[] __initconst = {
++ "apll1_div5",
++ "apll2_div5"
++};
++
++static const struct mtk_composite top_muxes[] __initconst = {
++ /* CLK_CFG_0 */
++ MUX(CLK_TOP_AXI_SEL, "axi_sel", axi_parents, 0x0040, 0, 3),
++ MUX(CLK_TOP_MEM_SEL, "mem_sel", mem_parents, 0x0040, 8, 1),
++ MUX_GATE(CLK_TOP_DDRPHYCFG_SEL, "ddrphycfg_sel", ddrphycfg_parents, 0x0040, 16, 1, 23),
++ MUX_GATE(CLK_TOP_MM_SEL, "mm_sel", mm_parents, 0x0040, 24, 4, 31),
++ /* CLK_CFG_1 */
++ MUX_GATE(CLK_TOP_PWM_SEL, "pwm_sel", pwm_parents, 0x0050, 0, 2, 7),
++ MUX_GATE(CLK_TOP_VDEC_SEL, "vdec_sel", vdec_parents, 0x0050, 8, 4, 15),
++ MUX_GATE(CLK_TOP_VENC_SEL, "venc_sel", venc_parents, 0x0050, 16, 4, 23),
++ MUX_GATE(CLK_TOP_MFG_SEL, "mfg_sel", mfg_parents, 0x0050, 24, 4, 31),
++ /* CLK_CFG_2 */
++ MUX_GATE(CLK_TOP_CAMTG_SEL, "camtg_sel", camtg_parents, 0x0060, 0, 3, 7),
++ MUX_GATE(CLK_TOP_UART_SEL, "uart_sel", uart_parents, 0x0060, 8, 1, 15),
++ MUX_GATE(CLK_TOP_SPI_SEL, "spi_sel", spi_parents, 0x0060, 16, 3, 23),
++ MUX_GATE(CLK_TOP_USB20_SEL, "usb20_sel", usb20_parents, 0x0060, 24, 2, 31),
++ /* CLK_CFG_3 */
++ MUX_GATE(CLK_TOP_USB30_SEL, "usb30_sel", usb30_parents, 0x0070, 0, 2, 7),
++ MUX_GATE(CLK_TOP_MSDC50_0_H_SEL, "msdc50_0_h_sel", msdc50_0_h_parents, 0x0070, 8, 3, 15),
++ MUX_GATE(CLK_TOP_MSDC50_0_SEL, "msdc50_0_sel", msdc50_0_parents, 0x0070, 16, 4, 23),
++ MUX_GATE(CLK_TOP_MSDC30_1_SEL, "msdc30_1_sel", msdc30_1_parents, 0x0070, 24, 3, 31),
++ /* CLK_CFG_4 */
++ MUX_GATE(CLK_TOP_MSDC30_2_SEL, "msdc30_2_sel", msdc30_2_parents, 0x0080, 0, 3, 7),
++ MUX_GATE(CLK_TOP_MSDC30_3_SEL, "msdc30_3_sel", msdc30_3_parents, 0x0080, 8, 4, 15),
++ MUX_GATE(CLK_TOP_AUDIO_SEL, "audio_sel", audio_parents, 0x0080, 16, 2, 23),
++ MUX_GATE(CLK_TOP_AUD_INTBUS_SEL, "aud_intbus_sel", aud_intbus_parents, 0x0080, 24, 3, 31),
++ /* CLK_CFG_5 */
++ MUX_GATE(CLK_TOP_PMICSPI_SEL, "pmicspi_sel", pmicspi_parents, 0x0090, 0, 3, 7 /* 7:5 */),
++ MUX_GATE(CLK_TOP_SCP_SEL, "scp_sel", scp_parents, 0x0090, 8, 3, 15),
++ MUX_GATE(CLK_TOP_ATB_SEL, "atb_sel", atb_parents, 0x0090, 16, 2, 23),
++ MUX_GATE(CLK_TOP_VENC_LT_SEL, "venclt_sel", venc_lt_parents, 0x0090, 24, 4, 31),
++ /* CLK_CFG_6 */
++ MUX_GATE(CLK_TOP_DPI0_SEL, "dpi0_sel", dpi0_parents, 0x00a0, 0, 3, 7),
++ MUX_GATE(CLK_TOP_IRDA_SEL, "irda_sel", irda_parents, 0x00a0, 8, 2, 15),
++ MUX_GATE(CLK_TOP_CCI400_SEL, "cci400_sel", cci400_parents, 0x00a0, 16, 3, 23),
++ MUX_GATE(CLK_TOP_AUD_1_SEL, "aud_1_sel", aud_1_parents, 0x00a0, 24, 2, 31),
++ /* CLK_CFG_7 */
++ MUX_GATE(CLK_TOP_AUD_2_SEL, "aud_2_sel", aud_2_parents, 0x00b0, 0, 2, 7),
++ MUX_GATE(CLK_TOP_MEM_MFG_IN_SEL, "mem_mfg_in_sel", mem_mfg_in_parents, 0x00b0, 8, 2, 15),
++ MUX_GATE(CLK_TOP_AXI_MFG_IN_SEL, "axi_mfg_in_sel", axi_mfg_in_parents, 0x00b0, 16, 2, 23),
++ MUX_GATE(CLK_TOP_SCAM_SEL, "scam_sel", scam_parents, 0x00b0, 24, 2, 31),
++ /* CLK_CFG_12 */
++ MUX_GATE(CLK_TOP_SPINFI_IFR_SEL, "spinfi_ifr_sel", spinfi_ifr_parents, 0x00c0, 0, 3, 7),
++ MUX_GATE(CLK_TOP_HDMI_SEL, "hdmi_sel", hdmi_parents, 0x00c0, 8, 2, 15),
++ MUX_GATE(CLK_TOP_DPILVDS_SEL, "dpilvds_sel", dpilvds_parents, 0x00c0, 24, 3, 31),
++ /* CLK_CFG_13 */
++ MUX_GATE(CLK_TOP_MSDC50_2_H_SEL, "msdc50_2_h_sel", msdc50_2_h_parents, 0x00d0, 0, 3, 7),
++ MUX_GATE(CLK_TOP_HDCP_SEL, "hdcp_sel", hdcp_parents, 0x00d0, 8, 2, 15),
++ MUX_GATE(CLK_TOP_HDCP_24M_SEL, "hdcp_24m_sel", hdcp_24m_parents, 0x00d0, 16, 2, 23),
++ MUX(CLK_TOP_RTC_SEL, "rtc_sel", rtc_parents, 0x00d0, 24, 2),
++
++ DIV_GATE(CLK_TOP_APLL1_DIV0, "apll1_div0", "aud_1_sel", 0x12c, 8, 0x120, 4, 24),
++ DIV_GATE(CLK_TOP_APLL1_DIV1, "apll1_div1", "aud_1_sel", 0x12c, 9, 0x124, 8, 0),
++ DIV_GATE(CLK_TOP_APLL1_DIV2, "apll1_div2", "aud_1_sel", 0x12c, 10, 0x124, 8, 8),
++ DIV_GATE(CLK_TOP_APLL1_DIV3, "apll1_div3", "aud_1_sel", 0x12c, 11, 0x124, 8, 16),
++ DIV_GATE(CLK_TOP_APLL1_DIV4, "apll1_div4", "aud_1_sel", 0x12c, 12, 0x124, 8, 24),
++ DIV_GATE(CLK_TOP_APLL1_DIV5, "apll1_div5", "apll1_div4", 0x12c, 13, 0x12c, 4, 0),
++
++ DIV_GATE(CLK_TOP_APLL2_DIV0, "apll2_div0", "aud_2_sel", 0x12c, 16, 0x120, 4, 28),
++ DIV_GATE(CLK_TOP_APLL2_DIV1, "apll2_div1", "aud_2_sel", 0x12c, 17, 0x128, 8, 0),
++ DIV_GATE(CLK_TOP_APLL2_DIV2, "apll2_div2", "aud_2_sel", 0x12c, 18, 0x128, 8, 8),
++ DIV_GATE(CLK_TOP_APLL2_DIV3, "apll2_div3", "aud_2_sel", 0x12c, 19, 0x128, 8, 16),
++ DIV_GATE(CLK_TOP_APLL2_DIV4, "apll2_div4", "aud_2_sel", 0x12c, 20, 0x128, 8, 24),
++ DIV_GATE(CLK_TOP_APLL2_DIV5, "apll2_div5", "apll2_div4", 0x12c, 21, 0x12c, 4, 4),
++
++ MUX(CLK_TOP_I2S0_M_SEL, "i2s0_m_ck_sel", i2s0_m_ck_parents, 0x120, 4, 1),
++ MUX(CLK_TOP_I2S1_M_SEL, "i2s1_m_ck_sel", i2s1_m_ck_parents, 0x120, 5, 1),
++ MUX(CLK_TOP_I2S2_M_SEL, "i2s2_m_ck_sel", i2s2_m_ck_parents, 0x120, 6, 1),
++ MUX(CLK_TOP_I2S3_M_SEL, "i2s3_m_ck_sel", i2s3_m_ck_parents, 0x120, 7, 1),
++ MUX(CLK_TOP_I2S3_B_SEL, "i2s3_b_ck_sel", i2s3_b_ck_parents, 0x120, 8, 1),
++};
++
++static const struct mtk_gate_regs infra_cg_regs = {
++ .set_ofs = 0x0040,
++ .clr_ofs = 0x0044,
++ .sta_ofs = 0x0048,
++};
++
++#define GATE_ICG(_id, _name, _parent, _shift) { \
++ .id = _id, \
++ .name = _name, \
++ .parent_name = _parent, \
++ .regs = &infra_cg_regs, \
++ .shift = _shift, \
++ .ops = &mtk_clk_gate_ops_setclr, \
++ }
++
++static const struct mtk_gate infra_clks[] __initconst = {
++ GATE_ICG(CLK_INFRA_DBGCLK, "infra_dbgclk", "axi_sel", 0),
++ GATE_ICG(CLK_INFRA_SMI, "infra_smi", "mm_sel", 1),
++ GATE_ICG(CLK_INFRA_AUDIO, "infra_audio", "aud_intbus_sel", 5),
++ GATE_ICG(CLK_INFRA_GCE, "infra_gce", "axi_sel", 6),
++ GATE_ICG(CLK_INFRA_L2C_SRAM, "infra_l2c_sram", "axi_sel", 7),
++ GATE_ICG(CLK_INFRA_M4U, "infra_m4u", "mem_sel", 8),
++ GATE_ICG(CLK_INFRA_CPUM, "infra_cpum", "clk_null", 15),
++ GATE_ICG(CLK_INFRA_KP, "infra_kp", "axi_sel", 16),
++ GATE_ICG(CLK_INFRA_CEC, "infra_cec", "clk26m", 18),
++ GATE_ICG(CLK_INFRA_PMICSPI, "infra_pmicspi", "pmicspi_sel", 22),
++ GATE_ICG(CLK_INFRA_PMICWRAP, "infra_pmicwrap", "axi_sel", 23),
++};
++
++static const struct mtk_gate_regs peri0_cg_regs = {
++ .set_ofs = 0x0008,
++ .clr_ofs = 0x0010,
++ .sta_ofs = 0x0018,
++};
++
++static const struct mtk_gate_regs peri1_cg_regs = {
++ .set_ofs = 0x000c,
++ .clr_ofs = 0x0014,
++ .sta_ofs = 0x001c,
++};
++
++#define GATE_PERI0(_id, _name, _parent, _shift) { \
++ .id = _id, \
++ .name = _name, \
++ .parent_name = _parent, \
++ .regs = &peri0_cg_regs, \
++ .shift = _shift, \
++ .ops = &mtk_clk_gate_ops_setclr, \
++ }
++
++#define GATE_PERI1(_id, _name, _parent, _shift) { \
++ .id = _id, \
++ .name = _name, \
++ .parent_name = _parent, \
++ .regs = &peri1_cg_regs, \
++ .shift = _shift, \
++ .ops = &mtk_clk_gate_ops_setclr, \
++ }
++
++static const struct mtk_gate peri_gates[] __initconst = {
++ /* PERI0 */
++ GATE_PERI0(CLK_PERI_NFI, "peri_nfi", "axi_sel", 0),
++ GATE_PERI0(CLK_PERI_THERM, "peri_therm", "axi_sel", 1),
++ GATE_PERI0(CLK_PERI_PWM1, "peri_pwm1", "axi_sel", 2),
++ GATE_PERI0(CLK_PERI_PWM2, "peri_pwm2", "axi_sel", 3),
++ GATE_PERI0(CLK_PERI_PWM3, "peri_pwm3", "axi_sel", 4),
++ GATE_PERI0(CLK_PERI_PWM4, "peri_pwm4", "axi_sel", 5),
++ GATE_PERI0(CLK_PERI_PWM5, "peri_pwm5", "axi_sel", 6),
++ GATE_PERI0(CLK_PERI_PWM6, "peri_pwm6", "axi_sel", 7),
++ GATE_PERI0(CLK_PERI_PWM7, "peri_pwm7", "axi_sel", 8),
++ GATE_PERI0(CLK_PERI_PWM, "peri_pwm", "axi_sel", 9),
++ GATE_PERI0(CLK_PERI_USB0, "peri_usb0", "usb20_sel", 10),
++ GATE_PERI0(CLK_PERI_USB1, "peri_usb1", "usb20_sel", 11),
++ GATE_PERI0(CLK_PERI_AP_DMA, "peri_ap_dma", "axi_sel", 12),
++ GATE_PERI0(CLK_PERI_MSDC30_0, "peri_msdc30_0", "msdc50_0_sel", 13),
++ GATE_PERI0(CLK_PERI_MSDC30_1, "peri_msdc30_1", "msdc30_1_sel", 14),
++ GATE_PERI0(CLK_PERI_MSDC30_2, "peri_msdc30_2", "msdc30_2_sel", 15),
++ GATE_PERI0(CLK_PERI_MSDC30_3, "peri_msdc30_3", "msdc30_3_sel", 16),
++ GATE_PERI0(CLK_PERI_NLI_ARB, "peri_nli_arb", "axi_sel", 17),
++ GATE_PERI0(CLK_PERI_IRDA, "peri_irda", "irda_sel", 18),
++ GATE_PERI0(CLK_PERI_UART0, "peri_uart0", "axi_sel", 19),
++ GATE_PERI0(CLK_PERI_UART1, "peri_uart1", "axi_sel", 20),
++ GATE_PERI0(CLK_PERI_UART2, "peri_uart2", "axi_sel", 21),
++ GATE_PERI0(CLK_PERI_UART3, "peri_uart3", "axi_sel", 22),
++ GATE_PERI0(CLK_PERI_I2C0, "peri_i2c0", "axi_sel", 23),
++ GATE_PERI0(CLK_PERI_I2C1, "peri_i2c1", "axi_sel", 24),
++ GATE_PERI0(CLK_PERI_I2C2, "peri_i2c2", "axi_sel", 25),
++ GATE_PERI0(CLK_PERI_I2C3, "peri_i2c3", "axi_sel", 26),
++ GATE_PERI0(CLK_PERI_I2C4, "peri_i2c4", "axi_sel", 27),
++ GATE_PERI0(CLK_PERI_AUXADC, "peri_auxadc", "clk26m", 28),
++ GATE_PERI0(CLK_PERI_SPI0, "peri_spi0", "spi_sel", 29),
++ GATE_PERI0(CLK_PERI_I2C5, "peri_i2c5", "axi_sel", 30),
++ GATE_PERI0(CLK_PERI_NFIECC, "peri_nfiecc", "axi_sel", 31),
++ /* PERI1 */
++ GATE_PERI1(CLK_PERI_SPI, "peri_spi", "spi_sel", 0),
++ GATE_PERI1(CLK_PERI_IRRX, "peri_irrx", "spi_sel", 1),
++ GATE_PERI1(CLK_PERI_I2C6, "peri_i2c6", "axi_sel", 2),
++};
++
++static const char * const uart_ck_sel_parents[] __initconst = {
++ "clk26m",
++ "uart_sel",
++};
++
++static const struct mtk_composite peri_clks[] __initconst = {
++ MUX(CLK_PERI_UART0_SEL, "uart0_ck_sel", uart_ck_sel_parents, 0x40c, 0, 1),
++ MUX(CLK_PERI_UART1_SEL, "uart1_ck_sel", uart_ck_sel_parents, 0x40c, 1, 1),
++ MUX(CLK_PERI_UART2_SEL, "uart2_ck_sel", uart_ck_sel_parents, 0x40c, 2, 1),
++ MUX(CLK_PERI_UART3_SEL, "uart3_ck_sel", uart_ck_sel_parents, 0x40c, 3, 1),
++};
++
++static void __init mtk_topckgen_init(struct device_node *node)
++{
++ struct clk_onecell_data *clk_data;
++ void __iomem *base;
++ int r;
++
++ base = of_iomap(node, 0);
++ if (!base) {
++ pr_err("%s(): ioremap failed\n", __func__);
++ return;
++ }
++
++ clk_data = mtk_alloc_clk_data(CLK_TOP_NR_CLK);
++
++ mtk_clk_register_factors(root_clk_alias, ARRAY_SIZE(root_clk_alias), clk_data);
++ mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs), clk_data);
++ mtk_clk_register_composites(top_muxes, ARRAY_SIZE(top_muxes), base,
++ &mt8173_clk_lock, clk_data);
++
++ clk_prepare_enable(clk_data->clks[CLK_TOP_CCI400_SEL]);
++
++ r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
++ if (r)
++ pr_err("%s(): could not register clock provider: %d\n",
++ __func__, r);
++}
++CLK_OF_DECLARE(mtk_topckgen, "mediatek,mt8173-topckgen", mtk_topckgen_init);
++
++static void __init mtk_infrasys_init(struct device_node *node)
++{
++ struct clk_onecell_data *clk_data;
++ int r;
++
++ clk_data = mtk_alloc_clk_data(CLK_INFRA_NR_CLK);
++
++ mtk_clk_register_gates(node, infra_clks, ARRAY_SIZE(infra_clks),
++ clk_data);
++
++ r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
++ if (r)
++ pr_err("%s(): could not register clock provider: %d\n",
++ __func__, r);
++
++ mtk_register_reset_controller(node, 2, 0x30);
++}
++CLK_OF_DECLARE(mtk_infrasys, "mediatek,mt8173-infracfg", mtk_infrasys_init);
++
++static void __init mtk_pericfg_init(struct device_node *node)
++{
++ struct clk_onecell_data *clk_data;
++ int r;
++ void __iomem *base;
++
++ base = of_iomap(node, 0);
++ if (!base) {
++ pr_err("%s(): ioremap failed\n", __func__);
++ return;
++ }
++
++ clk_data = mtk_alloc_clk_data(CLK_PERI_NR_CLK);
++
++ mtk_clk_register_gates(node, peri_gates, ARRAY_SIZE(peri_gates),
++ clk_data);
++ mtk_clk_register_composites(peri_clks, ARRAY_SIZE(peri_clks), base,
++ &mt8173_clk_lock, clk_data);
++
++ r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
++ if (r)
++ pr_err("%s(): could not register clock provider: %d\n",
++ __func__, r);
++
++ mtk_register_reset_controller(node, 2, 0);
++}
++CLK_OF_DECLARE(mtk_pericfg, "mediatek,mt8173-pericfg", mtk_pericfg_init);
++
++#define MT8173_PLL_FMAX (3000UL * MHZ)
++
++#define CON0_MT8173_RST_BAR BIT(24)
++
++#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, _pd_reg, _pd_shift, \
++ _tuner_reg, _pcw_reg, _pcw_shift) { \
++ .id = _id, \
++ .name = _name, \
++ .reg = _reg, \
++ .pwr_reg = _pwr_reg, \
++ .en_mask = _en_mask, \
++ .flags = _flags, \
++ .rst_bar_mask = CON0_MT8173_RST_BAR, \
++ .fmax = MT8173_PLL_FMAX, \
++ .pcwbits = _pcwbits, \
++ .pd_reg = _pd_reg, \
++ .pd_shift = _pd_shift, \
++ .tuner_reg = _tuner_reg, \
++ .pcw_reg = _pcw_reg, \
++ .pcw_shift = _pcw_shift, \
++ }
++
++static const struct mtk_pll_data plls[] = {
++ PLL(CLK_APMIXED_ARMCA15PLL, "armca15pll", 0x200, 0x20c, 0x00000001, 0, 21, 0x204, 24, 0x0, 0x204, 0),
++ PLL(CLK_APMIXED_ARMCA7PLL, "armca7pll", 0x210, 0x21c, 0x00000001, 0, 21, 0x214, 24, 0x0, 0x214, 0),
++ PLL(CLK_APMIXED_MAINPLL, "mainpll", 0x220, 0x22c, 0xf0000101, HAVE_RST_BAR, 21, 0x220, 4, 0x0, 0x224, 0),
++ PLL(CLK_APMIXED_UNIVPLL, "univpll", 0x230, 0x23c, 0xfe000001, HAVE_RST_BAR, 7, 0x230, 4, 0x0, 0x234, 14),
++ PLL(CLK_APMIXED_MMPLL, "mmpll", 0x240, 0x24c, 0x00000001, 0, 21, 0x244, 24, 0x0, 0x244, 0),
++ PLL(CLK_APMIXED_MSDCPLL, "msdcpll", 0x250, 0x25c, 0x00000001, 0, 21, 0x250, 4, 0x0, 0x254, 0),
++ PLL(CLK_APMIXED_VENCPLL, "vencpll", 0x260, 0x26c, 0x00000001, 0, 21, 0x260, 4, 0x0, 0x264, 0),
++ PLL(CLK_APMIXED_TVDPLL, "tvdpll", 0x270, 0x27c, 0x00000001, 0, 21, 0x270, 4, 0x0, 0x274, 0),
++ PLL(CLK_APMIXED_MPLL, "mpll", 0x280, 0x28c, 0x00000001, 0, 21, 0x280, 4, 0x0, 0x284, 0),
++ PLL(CLK_APMIXED_VCODECPLL, "vcodecpll", 0x290, 0x29c, 0x00000001, 0, 21, 0x290, 4, 0x0, 0x294, 0),
++ PLL(CLK_APMIXED_APLL1, "apll1", 0x2a0, 0x2b0, 0x00000001, 0, 31, 0x2a0, 4, 0x2a4, 0x2a4, 0),
++ PLL(CLK_APMIXED_APLL2, "apll2", 0x2b4, 0x2c4, 0x00000001, 0, 31, 0x2b4, 4, 0x2b8, 0x2b8, 0),
++ PLL(CLK_APMIXED_LVDSPLL, "lvdspll", 0x2d0, 0x2dc, 0x00000001, 0, 21, 0x2d0, 4, 0x0, 0x2d4, 0),
++ PLL(CLK_APMIXED_MSDCPLL2, "msdcpll2", 0x2f0, 0x2fc, 0x00000001, 0, 21, 0x2f0, 4, 0x0, 0x2f4, 0),
++};
++
++static void __init mtk_apmixedsys_init(struct device_node *node)
++{
++ struct clk_onecell_data *clk_data;
++
++ clk_data = mtk_alloc_clk_data(ARRAY_SIZE(plls));
++ if (!clk_data)
++ return;
++
++ mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data);
++
++ clk_prepare_enable(clk_data->clks[CLK_APMIXED_ARMCA15PLL]);
++}
++CLK_OF_DECLARE(mtk_apmixedsys, "mediatek,mt8173-apmixedsys",
++ mtk_apmixedsys_init);
+diff --git a/include/dt-bindings/clock/mt8173-clk.h b/include/dt-bindings/clock/mt8173-clk.h
+new file mode 100644
+index 0000000..4ad76ed
+--- /dev/null
++++ b/include/dt-bindings/clock/mt8173-clk.h
+@@ -0,0 +1,235 @@
++/*
++ * Copyright (c) 2014 MediaTek Inc.
++ * Author: James Liao <jamesjj.liao@mediatek.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#ifndef _DT_BINDINGS_CLK_MT8173_H
++#define _DT_BINDINGS_CLK_MT8173_H
++
++/* TOPCKGEN */
++
++#define CLK_TOP_CLKPH_MCK_O 1
++#define CLK_TOP_DPI 2
++#define CLK_TOP_USB_SYSPLL_125M 3
++#define CLK_TOP_HDMITX_DIG_CTS 4
++#define CLK_TOP_ARMCA7PLL_754M 5
++#define CLK_TOP_ARMCA7PLL_502M 6
++#define CLK_TOP_MAIN_H546M 7
++#define CLK_TOP_MAIN_H364M 8
++#define CLK_TOP_MAIN_H218P4M 9
++#define CLK_TOP_MAIN_H156M 10
++#define CLK_TOP_TVDPLL_445P5M 11
++#define CLK_TOP_TVDPLL_594M 12
++#define CLK_TOP_UNIV_624M 13
++#define CLK_TOP_UNIV_416M 14
++#define CLK_TOP_UNIV_249P6M 15
++#define CLK_TOP_UNIV_178P3M 16
++#define CLK_TOP_UNIV_48M 17
++#define CLK_TOP_CLKRTC_EXT 18
++#define CLK_TOP_CLKRTC_INT 19
++#define CLK_TOP_FPC 20
++#define CLK_TOP_HDMITXPLL_D2 21
++#define CLK_TOP_HDMITXPLL_D3 22
++#define CLK_TOP_ARMCA7PLL_D2 23
++#define CLK_TOP_ARMCA7PLL_D3 24
++#define CLK_TOP_APLL1 25
++#define CLK_TOP_APLL2 26
++#define CLK_TOP_DMPLL 27
++#define CLK_TOP_DMPLL_D2 28
++#define CLK_TOP_DMPLL_D4 29
++#define CLK_TOP_DMPLL_D8 30
++#define CLK_TOP_DMPLL_D16 31
++#define CLK_TOP_LVDSPLL_D2 32
++#define CLK_TOP_LVDSPLL_D4 33
++#define CLK_TOP_LVDSPLL_D8 34
++#define CLK_TOP_MMPLL 35
++#define CLK_TOP_MMPLL_D2 36
++#define CLK_TOP_MSDCPLL 37
++#define CLK_TOP_MSDCPLL_D2 38
++#define CLK_TOP_MSDCPLL_D4 39
++#define CLK_TOP_MSDCPLL2 40
++#define CLK_TOP_MSDCPLL2_D2 41
++#define CLK_TOP_MSDCPLL2_D4 42
++#define CLK_TOP_SYSPLL_D2 43
++#define CLK_TOP_SYSPLL1_D2 44
++#define CLK_TOP_SYSPLL1_D4 45
++#define CLK_TOP_SYSPLL1_D8 46
++#define CLK_TOP_SYSPLL1_D16 47
++#define CLK_TOP_SYSPLL_D3 48
++#define CLK_TOP_SYSPLL2_D2 49
++#define CLK_TOP_SYSPLL2_D4 50
++#define CLK_TOP_SYSPLL_D5 51
++#define CLK_TOP_SYSPLL3_D2 52
++#define CLK_TOP_SYSPLL3_D4 53
++#define CLK_TOP_SYSPLL_D7 54
++#define CLK_TOP_SYSPLL4_D2 55
++#define CLK_TOP_SYSPLL4_D4 56
++#define CLK_TOP_TVDPLL 57
++#define CLK_TOP_TVDPLL_D2 58
++#define CLK_TOP_TVDPLL_D4 59
++#define CLK_TOP_TVDPLL_D8 60
++#define CLK_TOP_TVDPLL_D16 61
++#define CLK_TOP_UNIVPLL_D2 62
++#define CLK_TOP_UNIVPLL1_D2 63
++#define CLK_TOP_UNIVPLL1_D4 64
++#define CLK_TOP_UNIVPLL1_D8 65
++#define CLK_TOP_UNIVPLL_D3 66
++#define CLK_TOP_UNIVPLL2_D2 67
++#define CLK_TOP_UNIVPLL2_D4 68
++#define CLK_TOP_UNIVPLL2_D8 69
++#define CLK_TOP_UNIVPLL_D5 70
++#define CLK_TOP_UNIVPLL3_D2 71
++#define CLK_TOP_UNIVPLL3_D4 72
++#define CLK_TOP_UNIVPLL3_D8 73
++#define CLK_TOP_UNIVPLL_D7 74
++#define CLK_TOP_UNIVPLL_D26 75
++#define CLK_TOP_UNIVPLL_D52 76
++#define CLK_TOP_VCODECPLL 77
++#define CLK_TOP_VCODECPLL_370P5 78
++#define CLK_TOP_VENCPLL 79
++#define CLK_TOP_VENCPLL_D2 80
++#define CLK_TOP_VENCPLL_D4 81
++#define CLK_TOP_AXI_SEL 82
++#define CLK_TOP_MEM_SEL 83
++#define CLK_TOP_DDRPHYCFG_SEL 84
++#define CLK_TOP_MM_SEL 85
++#define CLK_TOP_PWM_SEL 86
++#define CLK_TOP_VDEC_SEL 87
++#define CLK_TOP_VENC_SEL 88
++#define CLK_TOP_MFG_SEL 89
++#define CLK_TOP_CAMTG_SEL 90
++#define CLK_TOP_UART_SEL 91
++#define CLK_TOP_SPI_SEL 92
++#define CLK_TOP_USB20_SEL 93
++#define CLK_TOP_USB30_SEL 94
++#define CLK_TOP_MSDC50_0_H_SEL 95
++#define CLK_TOP_MSDC50_0_SEL 96
++#define CLK_TOP_MSDC30_1_SEL 97
++#define CLK_TOP_MSDC30_2_SEL 98
++#define CLK_TOP_MSDC30_3_SEL 99
++#define CLK_TOP_AUDIO_SEL 100
++#define CLK_TOP_AUD_INTBUS_SEL 101
++#define CLK_TOP_PMICSPI_SEL 102
++#define CLK_TOP_SCP_SEL 103
++#define CLK_TOP_ATB_SEL 104
++#define CLK_TOP_VENC_LT_SEL 105
++#define CLK_TOP_DPI0_SEL 106
++#define CLK_TOP_IRDA_SEL 107
++#define CLK_TOP_CCI400_SEL 108
++#define CLK_TOP_AUD_1_SEL 109
++#define CLK_TOP_AUD_2_SEL 110
++#define CLK_TOP_MEM_MFG_IN_SEL 111
++#define CLK_TOP_AXI_MFG_IN_SEL 112
++#define CLK_TOP_SCAM_SEL 113
++#define CLK_TOP_SPINFI_IFR_SEL 114
++#define CLK_TOP_HDMI_SEL 115
++#define CLK_TOP_DPILVDS_SEL 116
++#define CLK_TOP_MSDC50_2_H_SEL 117
++#define CLK_TOP_HDCP_SEL 118
++#define CLK_TOP_HDCP_24M_SEL 119
++#define CLK_TOP_RTC_SEL 120
++#define CLK_TOP_APLL1_DIV0 121
++#define CLK_TOP_APLL1_DIV1 122
++#define CLK_TOP_APLL1_DIV2 123
++#define CLK_TOP_APLL1_DIV3 124
++#define CLK_TOP_APLL1_DIV4 125
++#define CLK_TOP_APLL1_DIV5 126
++#define CLK_TOP_APLL2_DIV0 127
++#define CLK_TOP_APLL2_DIV1 128
++#define CLK_TOP_APLL2_DIV2 129
++#define CLK_TOP_APLL2_DIV3 130
++#define CLK_TOP_APLL2_DIV4 131
++#define CLK_TOP_APLL2_DIV5 132
++#define CLK_TOP_I2S0_M_SEL 133
++#define CLK_TOP_I2S1_M_SEL 134
++#define CLK_TOP_I2S2_M_SEL 135
++#define CLK_TOP_I2S3_M_SEL 136
++#define CLK_TOP_I2S3_B_SEL 137
++#define CLK_TOP_NR_CLK 138
++
++/* APMIXED_SYS */
++
++#define CLK_APMIXED_ARMCA15PLL 1
++#define CLK_APMIXED_ARMCA7PLL 2
++#define CLK_APMIXED_MAINPLL 3
++#define CLK_APMIXED_UNIVPLL 4
++#define CLK_APMIXED_MMPLL 5
++#define CLK_APMIXED_MSDCPLL 6
++#define CLK_APMIXED_VENCPLL 7
++#define CLK_APMIXED_TVDPLL 8
++#define CLK_APMIXED_MPLL 9
++#define CLK_APMIXED_VCODECPLL 10
++#define CLK_APMIXED_APLL1 11
++#define CLK_APMIXED_APLL2 12
++#define CLK_APMIXED_LVDSPLL 13
++#define CLK_APMIXED_MSDCPLL2 14
++#define CLK_APMIXED_NR_CLK 15
++
++/* INFRA_SYS */
++
++#define CLK_INFRA_DBGCLK 1
++#define CLK_INFRA_SMI 2
++#define CLK_INFRA_AUDIO 3
++#define CLK_INFRA_GCE 4
++#define CLK_INFRA_L2C_SRAM 5
++#define CLK_INFRA_M4U 6
++#define CLK_INFRA_CPUM 7
++#define CLK_INFRA_KP 8
++#define CLK_INFRA_CEC 9
++#define CLK_INFRA_PMICSPI 10
++#define CLK_INFRA_PMICWRAP 11
++#define CLK_INFRA_NR_CLK 12
++
++/* PERI_SYS */
++
++#define CLK_PERI_NFI 1
++#define CLK_PERI_THERM 2
++#define CLK_PERI_PWM1 3
++#define CLK_PERI_PWM2 4
++#define CLK_PERI_PWM3 5
++#define CLK_PERI_PWM4 6
++#define CLK_PERI_PWM5 7
++#define CLK_PERI_PWM6 8
++#define CLK_PERI_PWM7 9
++#define CLK_PERI_PWM 10
++#define CLK_PERI_USB0 11
++#define CLK_PERI_USB1 12
++#define CLK_PERI_AP_DMA 13
++#define CLK_PERI_MSDC30_0 14
++#define CLK_PERI_MSDC30_1 15
++#define CLK_PERI_MSDC30_2 16
++#define CLK_PERI_MSDC30_3 17
++#define CLK_PERI_NLI_ARB 18
++#define CLK_PERI_IRDA 19
++#define CLK_PERI_UART0 20
++#define CLK_PERI_UART1 21
++#define CLK_PERI_UART2 22
++#define CLK_PERI_UART3 23
++#define CLK_PERI_I2C0 24
++#define CLK_PERI_I2C1 25
++#define CLK_PERI_I2C2 26
++#define CLK_PERI_I2C3 27
++#define CLK_PERI_I2C4 28
++#define CLK_PERI_AUXADC 29
++#define CLK_PERI_SPI0 30
++#define CLK_PERI_I2C5 31
++#define CLK_PERI_NFIECC 32
++#define CLK_PERI_SPI 33
++#define CLK_PERI_IRRX 34
++#define CLK_PERI_I2C6 35
++#define CLK_PERI_UART0_SEL 36
++#define CLK_PERI_UART1_SEL 37
++#define CLK_PERI_UART2_SEL 38
++#define CLK_PERI_UART3_SEL 39
++#define CLK_PERI_NR_CLK 40
++
++#endif /* _DT_BINDINGS_CLK_MT8173_H */
+diff --git a/include/dt-bindings/reset-controller/mt8173-resets.h b/include/dt-bindings/reset-controller/mt8173-resets.h
+new file mode 100644
+index 0000000..9464b37
+--- /dev/null
++++ b/include/dt-bindings/reset-controller/mt8173-resets.h
+@@ -0,0 +1,63 @@
++/*
++ * Copyright (c) 2014 MediaTek Inc.
++ * Author: Flora Fu, MediaTek
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#ifndef _DT_BINDINGS_RESET_CONTROLLER_MT8173
++#define _DT_BINDINGS_RESET_CONTROLLER_MT8173
++
++/* INFRACFG resets */
++#define MT8173_INFRA_EMI_REG_RST 0
++#define MT8173_INFRA_DRAMC0_A0_RST 1
++#define MT8173_INFRA_APCIRQ_EINT_RST 3
++#define MT8173_INFRA_APXGPT_RST 4
++#define MT8173_INFRA_SCPSYS_RST 5
++#define MT8173_INFRA_KP_RST 6
++#define MT8173_INFRA_PMIC_WRAP_RST 7
++#define MT8173_INFRA_MPIP_RST 8
++#define MT8173_INFRA_CEC_RST 9
++#define MT8173_INFRA_EMI_RST 32
++#define MT8173_INFRA_DRAMC0_RST 34
++#define MT8173_INFRA_APMIXEDSYS_RST 35
++#define MT8173_INFRA_MIPI_DSI_RST 36
++#define MT8173_INFRA_TRNG_RST 37
++#define MT8173_INFRA_SYSIRQ_RST 38
++#define MT8173_INFRA_MIPI_CSI_RST 39
++#define MT8173_INFRA_GCE_FAXI_RST 40
++#define MT8173_INFRA_MMIOMMURST 47
++
++
++/* PERICFG resets */
++#define MT8173_PERI_UART0_SW_RST 0
++#define MT8173_PERI_UART1_SW_RST 1
++#define MT8173_PERI_UART2_SW_RST 2
++#define MT8173_PERI_UART3_SW_RST 3
++#define MT8173_PERI_IRRX_SW_RST 4
++#define MT8173_PERI_PWM_SW_RST 8
++#define MT8173_PERI_AUXADC_SW_RST 10
++#define MT8173_PERI_DMA_SW_RST 11
++#define MT8173_PERI_I2C6_SW_RST 13
++#define MT8173_PERI_NFI_SW_RST 14
++#define MT8173_PERI_THERM_SW_RST 16
++#define MT8173_PERI_MSDC2_SW_RST 17
++#define MT8173_PERI_MSDC3_SW_RST 18
++#define MT8173_PERI_MSDC0_SW_RST 19
++#define MT8173_PERI_MSDC1_SW_RST 20
++#define MT8173_PERI_I2C0_SW_RST 22
++#define MT8173_PERI_I2C1_SW_RST 23
++#define MT8173_PERI_I2C2_SW_RST 24
++#define MT8173_PERI_I2C3_SW_RST 25
++#define MT8173_PERI_I2C4_SW_RST 26
++#define MT8173_PERI_HDMI_SW_RST 29
++#define MT8173_PERI_SPI0_SW_RST 33
++
++#endif /* _DT_BINDINGS_RESET_CONTROLLER_MT8173 */
+--
+1.7.10.4
+
--- /dev/null
+From d6d7a7dc1b7db2e3d496bf67b30abc894edbc4bd Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer@pengutronix.de>
+Date: Tue, 9 Jun 2015 10:46:59 +0200
+Subject: [PATCH 06/76] soc: mediatek: Add infracfg misc driver support
+
+This adds support for some miscellaneous bits of the infracfg controller.
+The mtk_infracfg_set/clear_bus_protection functions are necessary for
+the scpsys power domain driver to handle the bus protection bits which
+are contained in the infacfg register space.
+
+Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
+---
+ drivers/soc/mediatek/Kconfig | 9 ++++
+ drivers/soc/mediatek/Makefile | 1 +
+ drivers/soc/mediatek/mtk-infracfg.c | 91 +++++++++++++++++++++++++++++++++
+ include/linux/soc/mediatek/infracfg.h | 26 ++++++++++
+ 4 files changed, 127 insertions(+)
+ create mode 100644 drivers/soc/mediatek/mtk-infracfg.c
+ create mode 100644 include/linux/soc/mediatek/infracfg.h
+
+diff --git a/drivers/soc/mediatek/Kconfig b/drivers/soc/mediatek/Kconfig
+index 3c18503..09da41e 100644
+--- a/drivers/soc/mediatek/Kconfig
++++ b/drivers/soc/mediatek/Kconfig
+@@ -1,6 +1,15 @@
+ #
+ # MediaTek SoC drivers
+ #
++config MTK_INFRACFG
++ bool "MediaTek INFRACFG Support"
++ depends on ARCH_MEDIATEK
++ select REGMAP
++ help
++ Say yes here to add support for the MediaTek INFRACFG controller. The
++ INFRACFG controller contains various infrastructure registers not
++ directly associated to any device.
++
+ config MTK_PMIC_WRAP
+ tristate "MediaTek PMIC Wrapper Support"
+ depends on ARCH_MEDIATEK
+diff --git a/drivers/soc/mediatek/Makefile b/drivers/soc/mediatek/Makefile
+index ecaf4de..3fa940f 100644
+--- a/drivers/soc/mediatek/Makefile
++++ b/drivers/soc/mediatek/Makefile
+@@ -1 +1,2 @@
++obj-$(CONFIG_MTK_INFRACFG) += mtk-infracfg.o
+ obj-$(CONFIG_MTK_PMIC_WRAP) += mtk-pmic-wrap.o
+diff --git a/drivers/soc/mediatek/mtk-infracfg.c b/drivers/soc/mediatek/mtk-infracfg.c
+new file mode 100644
+index 0000000..ca786e0
+--- /dev/null
++++ b/drivers/soc/mediatek/mtk-infracfg.c
+@@ -0,0 +1,91 @@
++/*
++ * Copyright (c) 2015 Pengutronix, Sascha Hauer <kernel@pengutronix.de>
++ *
++ * 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.
++ */
++
++#include <linux/export.h>
++#include <linux/jiffies.h>
++#include <linux/regmap.h>
++#include <linux/soc/mediatek/infracfg.h>
++#include <asm/processor.h>
++
++#define INFRA_TOPAXI_PROTECTEN 0x0220
++#define INFRA_TOPAXI_PROTECTSTA1 0x0228
++
++/**
++ * mtk_infracfg_set_bus_protection - enable bus protection
++ * @regmap: The infracfg regmap
++ * @mask: The mask containing the protection bits to be enabled.
++ *
++ * This function enables the bus protection bits for disabled power
++ * domains so that the system does not hanf when some unit accesses the
++ * bus while in power down.
++ */
++int mtk_infracfg_set_bus_protection(struct regmap *infracfg, u32 mask)
++{
++ unsigned long expired;
++ u32 val;
++ int ret;
++
++ regmap_update_bits(infracfg, INFRA_TOPAXI_PROTECTEN, mask, mask);
++
++ expired = jiffies + HZ;
++
++ while (1) {
++ ret = regmap_read(infracfg, INFRA_TOPAXI_PROTECTSTA1, &val);
++ if (ret)
++ return ret;
++
++ if ((val & mask) == mask)
++ break;
++
++ cpu_relax();
++ if (time_after(jiffies, expired))
++ return -EIO;
++ }
++
++ return 0;
++}
++
++/**
++ * mtk_infracfg_clear_bus_protection - disable bus protection
++ * @regmap: The infracfg regmap
++ * @mask: The mask containing the protection bits to be disabled.
++ *
++ * This function disables the bus protection bits previously enabled with
++ * mtk_infracfg_set_bus_protection.
++ */
++int mtk_infracfg_clear_bus_protection(struct regmap *infracfg, u32 mask)
++{
++ unsigned long expired;
++ int ret;
++
++ regmap_update_bits(infracfg, INFRA_TOPAXI_PROTECTEN, mask, 0);
++
++ expired = jiffies + HZ;
++
++ while (1) {
++ u32 val;
++
++ ret = regmap_read(infracfg, INFRA_TOPAXI_PROTECTSTA1, &val);
++ if (ret)
++ return ret;
++
++ if (!(val & mask))
++ break;
++
++ cpu_relax();
++ if (time_after(jiffies, expired))
++ return -EIO;
++ }
++
++ return 0;
++}
+diff --git a/include/linux/soc/mediatek/infracfg.h b/include/linux/soc/mediatek/infracfg.h
+new file mode 100644
+index 0000000..a5714e9
+--- /dev/null
++++ b/include/linux/soc/mediatek/infracfg.h
+@@ -0,0 +1,26 @@
++#ifndef __SOC_MEDIATEK_INFRACFG_H
++#define __SOC_MEDIATEK_INFRACFG_H
++
++#define MT8173_TOP_AXI_PROT_EN_MCI_M2 BIT(0)
++#define MT8173_TOP_AXI_PROT_EN_MM_M0 BIT(1)
++#define MT8173_TOP_AXI_PROT_EN_MM_M1 BIT(2)
++#define MT8173_TOP_AXI_PROT_EN_MMAPB_S BIT(6)
++#define MT8173_TOP_AXI_PROT_EN_L2C_M2 BIT(9)
++#define MT8173_TOP_AXI_PROT_EN_L2SS_SMI BIT(11)
++#define MT8173_TOP_AXI_PROT_EN_L2SS_ADD BIT(12)
++#define MT8173_TOP_AXI_PROT_EN_CCI_M2 BIT(13)
++#define MT8173_TOP_AXI_PROT_EN_MFG_S BIT(14)
++#define MT8173_TOP_AXI_PROT_EN_PERI_M0 BIT(15)
++#define MT8173_TOP_AXI_PROT_EN_PERI_M1 BIT(16)
++#define MT8173_TOP_AXI_PROT_EN_DEBUGSYS BIT(17)
++#define MT8173_TOP_AXI_PROT_EN_CQ_DMA BIT(18)
++#define MT8173_TOP_AXI_PROT_EN_GCPU BIT(19)
++#define MT8173_TOP_AXI_PROT_EN_IOMMU BIT(20)
++#define MT8173_TOP_AXI_PROT_EN_MFG_M0 BIT(21)
++#define MT8173_TOP_AXI_PROT_EN_MFG_M1 BIT(22)
++#define MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT BIT(23)
++
++int mtk_infracfg_set_bus_protection(struct regmap *infracfg, u32 mask);
++int mtk_infracfg_clear_bus_protection(struct regmap *infracfg, u32 mask);
++
++#endif /* __SOC_MEDIATEK_INFRACFG_H */
+--
+1.7.10.4
+
--- /dev/null
+From 06a1fd8a198771abc7c5badcf43a49a715ba4c76 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer@pengutronix.de>
+Date: Tue, 9 Jun 2015 10:47:00 +0200
+Subject: [PATCH 07/76] dt-bindings: soc: Add documentation for the MediaTek
+ SCPSYS unit
+
+This adds documentation for the MediaTek SCPSYS unit found in MT8173 SoCs.
+
+Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
+---
+ .../devicetree/bindings/soc/mediatek/scpsys.txt | 34 ++++++++++++++++++++
+ 1 file changed, 34 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/soc/mediatek/scpsys.txt
+
+diff --git a/Documentation/devicetree/bindings/soc/mediatek/scpsys.txt b/Documentation/devicetree/bindings/soc/mediatek/scpsys.txt
+new file mode 100644
+index 0000000..87f2091
+--- /dev/null
++++ b/Documentation/devicetree/bindings/soc/mediatek/scpsys.txt
+@@ -0,0 +1,34 @@
++MediaTek SCPSYS
++===============
++
++The System Control Processor System (SCPSYS) has several power management
++related tasks in the system. The tasks include thermal measurement, dynamic
++voltage frequency scaling (DVFS), interrupt filter and lowlevel sleep control.
++The System Power Manager (SPM) inside the SCPSYS is for the MTCMOS power
++domain control.
++
++The driver implements the Generic PM domain bindings described in
++power/power_domain.txt. It provides the power domains defined in
++include/dt-bindings/power/mt8173-power.h.
++
++Required properties:
++- compatible: Must be "mediatek,mt8173-scpsys"
++- #power-domain-cells: Must be 1
++- reg: Address range of the SCPSYS unit
++- infracfg: must contain a phandle to the infracfg controller
++
++Example:
++
++ scpsys: scpsys@10006000 {
++ #power-domain-cells = <1>;
++ compatible = "mediatek,mt8173-scpsys";
++ reg = <0 0x10006000 0 0x1000>;
++ infracfg = <&infracfg>;
++ };
++
++Example consumer:
++
++ afe: mt8173-afe-pcm@11220000 {
++ compatible = "mediatek,mt8173-afe-pcm";
++ power-domains = <&scpsys MT8173_POWER_DOMAIN_AUDIO>;
++ };
+--
+1.7.10.4
+
--- /dev/null
+From 04e2e2a895a95dc9e75403c2e8ea190dce9dc387 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer@pengutronix.de>
+Date: Tue, 9 Jun 2015 10:47:01 +0200
+Subject: [PATCH 08/76] soc: Mediatek: Add SCPSYS power domain driver
+
+This adds a power domain driver for the Mediatek SCPSYS unit.
+
+The System Control Processor System (SCPSYS) has several power
+management related tasks in the system. The tasks include thermal
+measurement, dynamic voltage frequency scaling (DVFS), interrupt
+filter and lowlevel sleep control. The System Power Manager (SPM)
+inside the SCPSYS is for the MTCMOS power domain control.
+
+For now this driver only adds power domain support, the more
+advanced features are not yet supported. The driver implements
+the generic PM domain device tree bindings, the first user will
+most likely be the Mediatek AFE audio driver.
+
+Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
+---
+ drivers/soc/mediatek/Kconfig | 9 +
+ drivers/soc/mediatek/Makefile | 1 +
+ drivers/soc/mediatek/mtk-scpsys.c | 490 ++++++++++++++++++++++++++++++
+ include/dt-bindings/power/mt8173-power.h | 15 +
+ 4 files changed, 515 insertions(+)
+ create mode 100644 drivers/soc/mediatek/mtk-scpsys.c
+ create mode 100644 include/dt-bindings/power/mt8173-power.h
+
+diff --git a/drivers/soc/mediatek/Kconfig b/drivers/soc/mediatek/Kconfig
+index 09da41e..2dc5d90 100644
+--- a/drivers/soc/mediatek/Kconfig
++++ b/drivers/soc/mediatek/Kconfig
+@@ -19,3 +19,12 @@ config MTK_PMIC_WRAP
+ Say yes here to add support for MediaTek PMIC Wrapper found
+ on different MediaTek SoCs. The PMIC wrapper is a proprietary
+ hardware to connect the PMIC.
++
++config MTK_SCPSYS
++ bool "MediaTek SCPSYS Support"
++ depends on ARCH_MEDIATEK || COMPILE_TEST
++ select REGMAP
++ select MTK_INFRACFG
++ help
++ Say yes here to add support for the MediaTek SCPSYS power domain
++ driver.
+diff --git a/drivers/soc/mediatek/Makefile b/drivers/soc/mediatek/Makefile
+index 3fa940f..12998b0 100644
+--- a/drivers/soc/mediatek/Makefile
++++ b/drivers/soc/mediatek/Makefile
+@@ -1,2 +1,3 @@
+ obj-$(CONFIG_MTK_INFRACFG) += mtk-infracfg.o
+ obj-$(CONFIG_MTK_PMIC_WRAP) += mtk-pmic-wrap.o
++obj-$(CONFIG_MTK_SCPSYS) += mtk-scpsys.o
+diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c
+new file mode 100644
+index 0000000..b9eed37
+--- /dev/null
++++ b/drivers/soc/mediatek/mtk-scpsys.c
+@@ -0,0 +1,490 @@
++/*
++ * Copyright (c) 2015 Pengutronix, Sascha Hauer <kernel@pengutronix.de>
++ *
++ * 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.
++ */
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/io.h>
++#include <linux/kernel.h>
++#include <linux/mfd/syscon.h>
++#include <linux/of_device.h>
++#include <linux/platform_device.h>
++#include <linux/pm_domain.h>
++#include <linux/regmap.h>
++#include <linux/soc/mediatek/infracfg.h>
++#include <dt-bindings/power/mt8173-power.h>
++
++#define SPM_VDE_PWR_CON 0x0210
++#define SPM_MFG_PWR_CON 0x0214
++#define SPM_VEN_PWR_CON 0x0230
++#define SPM_ISP_PWR_CON 0x0238
++#define SPM_DIS_PWR_CON 0x023c
++#define SPM_VEN2_PWR_CON 0x0298
++#define SPM_AUDIO_PWR_CON 0x029c
++#define SPM_MFG_2D_PWR_CON 0x02c0
++#define SPM_MFG_ASYNC_PWR_CON 0x02c4
++#define SPM_USB_PWR_CON 0x02cc
++#define SPM_PWR_STATUS 0x060c
++#define SPM_PWR_STATUS_2ND 0x0610
++
++#define PWR_RST_B_BIT BIT(0)
++#define PWR_ISO_BIT BIT(1)
++#define PWR_ON_BIT BIT(2)
++#define PWR_ON_2ND_BIT BIT(3)
++#define PWR_CLK_DIS_BIT BIT(4)
++
++#define PWR_STATUS_DISP BIT(3)
++#define PWR_STATUS_MFG BIT(4)
++#define PWR_STATUS_ISP BIT(5)
++#define PWR_STATUS_VDEC BIT(7)
++#define PWR_STATUS_VENC_LT BIT(20)
++#define PWR_STATUS_VENC BIT(21)
++#define PWR_STATUS_MFG_2D BIT(22)
++#define PWR_STATUS_MFG_ASYNC BIT(23)
++#define PWR_STATUS_AUDIO BIT(24)
++#define PWR_STATUS_USB BIT(25)
++
++enum clk_id {
++ MT8173_CLK_NONE,
++ MT8173_CLK_MM,
++ MT8173_CLK_MFG,
++ MT8173_CLK_MAX = MT8173_CLK_MFG,
++};
++
++struct scp_domain_data {
++ const char *name;
++ u32 sta_mask;
++ int ctl_offs;
++ u32 sram_pdn_bits;
++ u32 sram_pdn_ack_bits;
++ u32 bus_prot_mask;
++ enum clk_id clk_id;
++};
++
++static const struct scp_domain_data scp_domain_data[] __initconst = {
++ [MT8173_POWER_DOMAIN_VDEC] = {
++ .name = "vdec",
++ .sta_mask = PWR_STATUS_VDEC,
++ .ctl_offs = SPM_VDE_PWR_CON,
++ .sram_pdn_bits = GENMASK(11, 8),
++ .sram_pdn_ack_bits = GENMASK(12, 12),
++ .clk_id = MT8173_CLK_MM,
++ },
++ [MT8173_POWER_DOMAIN_VENC] = {
++ .name = "venc",
++ .sta_mask = PWR_STATUS_VENC,
++ .ctl_offs = SPM_VEN_PWR_CON,
++ .sram_pdn_bits = GENMASK(11, 8),
++ .sram_pdn_ack_bits = GENMASK(15, 12),
++ .clk_id = MT8173_CLK_MM,
++ },
++ [MT8173_POWER_DOMAIN_ISP] = {
++ .name = "isp",
++ .sta_mask = PWR_STATUS_ISP,
++ .ctl_offs = SPM_ISP_PWR_CON,
++ .sram_pdn_bits = GENMASK(11, 8),
++ .sram_pdn_ack_bits = GENMASK(13, 12),
++ .clk_id = MT8173_CLK_MM,
++ },
++ [MT8173_POWER_DOMAIN_MM] = {
++ .name = "mm",
++ .sta_mask = PWR_STATUS_DISP,
++ .ctl_offs = SPM_DIS_PWR_CON,
++ .sram_pdn_bits = GENMASK(11, 8),
++ .sram_pdn_ack_bits = GENMASK(12, 12),
++ .clk_id = MT8173_CLK_MM,
++ .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MM_M0 |
++ MT8173_TOP_AXI_PROT_EN_MM_M1,
++ },
++ [MT8173_POWER_DOMAIN_VENC_LT] = {
++ .name = "venc_lt",
++ .sta_mask = PWR_STATUS_VENC_LT,
++ .ctl_offs = SPM_VEN2_PWR_CON,
++ .sram_pdn_bits = GENMASK(11, 8),
++ .sram_pdn_ack_bits = GENMASK(15, 12),
++ .clk_id = MT8173_CLK_MM,
++ },
++ [MT8173_POWER_DOMAIN_AUDIO] = {
++ .name = "audio",
++ .sta_mask = PWR_STATUS_AUDIO,
++ .ctl_offs = SPM_AUDIO_PWR_CON,
++ .sram_pdn_bits = GENMASK(11, 8),
++ .sram_pdn_ack_bits = GENMASK(15, 12),
++ .clk_id = MT8173_CLK_NONE,
++ },
++ [MT8173_POWER_DOMAIN_USB] = {
++ .name = "usb",
++ .sta_mask = PWR_STATUS_USB,
++ .ctl_offs = SPM_USB_PWR_CON,
++ .sram_pdn_bits = GENMASK(11, 8),
++ .sram_pdn_ack_bits = GENMASK(15, 12),
++ .clk_id = MT8173_CLK_NONE,
++ },
++ [MT8173_POWER_DOMAIN_MFG_ASYNC] = {
++ .name = "mfg_async",
++ .sta_mask = PWR_STATUS_MFG_ASYNC,
++ .ctl_offs = SPM_MFG_ASYNC_PWR_CON,
++ .sram_pdn_bits = GENMASK(11, 8),
++ .sram_pdn_ack_bits = 0,
++ .clk_id = MT8173_CLK_MFG,
++ },
++ [MT8173_POWER_DOMAIN_MFG_2D] = {
++ .name = "mfg_2d",
++ .sta_mask = PWR_STATUS_MFG_2D,
++ .ctl_offs = SPM_MFG_2D_PWR_CON,
++ .sram_pdn_bits = GENMASK(11, 8),
++ .sram_pdn_ack_bits = GENMASK(13, 12),
++ .clk_id = MT8173_CLK_NONE,
++ },
++ [MT8173_POWER_DOMAIN_MFG] = {
++ .name = "mfg",
++ .sta_mask = PWR_STATUS_MFG,
++ .ctl_offs = SPM_MFG_PWR_CON,
++ .sram_pdn_bits = GENMASK(13, 8),
++ .sram_pdn_ack_bits = GENMASK(21, 16),
++ .clk_id = MT8173_CLK_NONE,
++ .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MFG_S |
++ MT8173_TOP_AXI_PROT_EN_MFG_M0 |
++ MT8173_TOP_AXI_PROT_EN_MFG_M1 |
++ MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT,
++ },
++};
++
++#define NUM_DOMAINS ARRAY_SIZE(scp_domain_data)
++
++struct scp;
++
++struct scp_domain {
++ struct generic_pm_domain genpd;
++ struct scp *scp;
++ struct clk *clk;
++ u32 sta_mask;
++ void __iomem *ctl_addr;
++ u32 sram_pdn_bits;
++ u32 sram_pdn_ack_bits;
++ u32 bus_prot_mask;
++};
++
++struct scp {
++ struct scp_domain domains[NUM_DOMAINS];
++ struct genpd_onecell_data pd_data;
++ struct device *dev;
++ void __iomem *base;
++ struct regmap *infracfg;
++ struct clk *clk[MT8173_CLK_MAX];
++};
++
++static int scpsys_domain_is_on(struct scp_domain *scpd)
++{
++ struct scp *scp = scpd->scp;
++
++ u32 status = readl(scp->base + SPM_PWR_STATUS) & scpd->sta_mask;
++ u32 status2 = readl(scp->base + SPM_PWR_STATUS_2ND) & scpd->sta_mask;
++
++ /*
++ * A domain is on when both status bits are set. If only one is set
++ * return an error. This happens while powering up a domain
++ */
++
++ if (status && status2)
++ return true;
++ if (!status && !status2)
++ return false;
++
++ return -EINVAL;
++}
++
++static int scpsys_power_on(struct generic_pm_domain *genpd)
++{
++ struct scp_domain *scpd = container_of(genpd, struct scp_domain, genpd);
++ struct scp *scp = scpd->scp;
++ unsigned long timeout;
++ bool expired;
++ void __iomem *ctl_addr = scpd->ctl_addr;
++ u32 sram_pdn_ack = scpd->sram_pdn_ack_bits;
++ u32 val;
++ int ret;
++
++ if (scpd->clk) {
++ ret = clk_prepare_enable(scpd->clk);
++ if (ret)
++ return ret;
++ }
++
++ val = readl(ctl_addr);
++ val |= PWR_ON_BIT;
++ writel(val, ctl_addr);
++ val |= PWR_ON_2ND_BIT;
++ writel(val, ctl_addr);
++
++ /* wait until PWR_ACK = 1 */
++ timeout = jiffies + HZ;
++ expired = false;
++ while (1) {
++ ret = scpsys_domain_is_on(scpd);
++ if (ret > 0)
++ break;
++
++ if (expired) {
++ ret = -ETIMEDOUT;
++ goto out;
++ }
++
++ cpu_relax();
++
++ if (time_after(jiffies, timeout))
++ expired = true;
++ }
++
++ val &= ~PWR_CLK_DIS_BIT;
++ writel(val, ctl_addr);
++
++ val &= ~PWR_ISO_BIT;
++ writel(val, ctl_addr);
++
++ val |= PWR_RST_B_BIT;
++ writel(val, ctl_addr);
++
++ val &= ~scpd->sram_pdn_bits;
++ writel(val, ctl_addr);
++
++ /* wait until SRAM_PDN_ACK all 0 */
++ timeout = jiffies + HZ;
++ expired = false;
++ while (sram_pdn_ack && (readl(ctl_addr) & sram_pdn_ack)) {
++
++ if (expired) {
++ ret = -ETIMEDOUT;
++ goto out;
++ }
++
++ cpu_relax();
++
++ if (time_after(jiffies, timeout))
++ expired = true;
++ }
++
++ if (scpd->bus_prot_mask) {
++ ret = mtk_infracfg_clear_bus_protection(scp->infracfg,
++ scpd->bus_prot_mask);
++ if (ret)
++ return ret;
++ }
++
++ return 0;
++out:
++ dev_err(scp->dev, "Failed to power on domain %s\n", genpd->name);
++
++ return ret;
++}
++
++static int scpsys_power_off(struct generic_pm_domain *genpd)
++{
++ struct scp_domain *scpd = container_of(genpd, struct scp_domain, genpd);
++ struct scp *scp = scpd->scp;
++ unsigned long timeout;
++ bool expired;
++ void __iomem *ctl_addr = scpd->ctl_addr;
++ u32 pdn_ack = scpd->sram_pdn_ack_bits;
++ u32 val;
++ int ret;
++
++ if (scpd->bus_prot_mask) {
++ ret = mtk_infracfg_set_bus_protection(scp->infracfg,
++ scpd->bus_prot_mask);
++ if (ret)
++ return ret;
++ }
++
++ val = readl(ctl_addr);
++ val |= scpd->sram_pdn_bits;
++ writel(val, ctl_addr);
++
++ /* wait until SRAM_PDN_ACK all 1 */
++ timeout = jiffies + HZ;
++ expired = false;
++ while (pdn_ack && (readl(ctl_addr) & pdn_ack) != pdn_ack) {
++ if (expired) {
++ ret = -ETIMEDOUT;
++ goto out;
++ }
++
++ cpu_relax();
++
++ if (time_after(jiffies, timeout))
++ expired = true;
++ }
++
++ val |= PWR_ISO_BIT;
++ writel(val, ctl_addr);
++
++ val &= ~PWR_RST_B_BIT;
++ writel(val, ctl_addr);
++
++ val |= PWR_CLK_DIS_BIT;
++ writel(val, ctl_addr);
++
++ val &= ~PWR_ON_BIT;
++ writel(val, ctl_addr);
++
++ val &= ~PWR_ON_2ND_BIT;
++ writel(val, ctl_addr);
++
++ /* wait until PWR_ACK = 0 */
++ timeout = jiffies + HZ;
++ expired = false;
++ while (1) {
++ ret = scpsys_domain_is_on(scpd);
++ if (ret == 0)
++ break;
++
++ if (expired) {
++ ret = -ETIMEDOUT;
++ goto out;
++ }
++
++ cpu_relax();
++
++ if (time_after(jiffies, timeout))
++ expired = true;
++ }
++
++ if (scpd->clk)
++ clk_disable_unprepare(scpd->clk);
++
++ return 0;
++
++out:
++ dev_err(scp->dev, "Failed to power off domain %s\n", genpd->name);
++
++ return ret;
++}
++
++static int __init scpsys_probe(struct platform_device *pdev)
++{
++ struct genpd_onecell_data *pd_data;
++ struct resource *res;
++ int i, ret;
++ struct scp *scp;
++
++ scp = devm_kzalloc(&pdev->dev, sizeof(*scp), GFP_KERNEL);
++ if (!scp)
++ return -ENOMEM;
++
++ scp->dev = &pdev->dev;
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ scp->base = devm_ioremap_resource(&pdev->dev, res);
++ if (IS_ERR(scp->base))
++ return PTR_ERR(scp->base);
++
++ pd_data = &scp->pd_data;
++
++ pd_data->domains = devm_kzalloc(&pdev->dev,
++ sizeof(*pd_data->domains) * NUM_DOMAINS, GFP_KERNEL);
++ if (!pd_data->domains)
++ return -ENOMEM;
++
++ scp->clk[MT8173_CLK_MM] = devm_clk_get(&pdev->dev, "mm");
++ if (IS_ERR(scp->clk[MT8173_CLK_MM])) {
++ dev_err(&pdev->dev, "Failed to get mm clk: %ld\n",
++ PTR_ERR(scp->clk[MT8173_CLK_MM]));
++ return PTR_ERR(scp->clk[MT8173_CLK_MM]);
++ }
++
++ scp->clk[MT8173_CLK_MFG] = devm_clk_get(&pdev->dev, "mfg");
++ if (IS_ERR(scp->clk[MT8173_CLK_MFG])) {
++ dev_err(&pdev->dev, "Failed to get mfg clk: %ld\n",
++ PTR_ERR(scp->clk[MT8173_CLK_MFG]));
++ return PTR_ERR(scp->clk[MT8173_CLK_MFG]);
++ }
++
++ scp->infracfg = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
++ "infracfg");
++ if (IS_ERR(scp->infracfg)) {
++ dev_err(&pdev->dev, "Cannot find infracfg controller: %ld\n",
++ PTR_ERR(scp->infracfg));
++ return PTR_ERR(scp->infracfg);
++ }
++
++ pd_data->num_domains = NUM_DOMAINS;
++
++ for (i = 0; i < NUM_DOMAINS; i++) {
++ struct scp_domain *scpd = &scp->domains[i];
++ struct generic_pm_domain *genpd = &scpd->genpd;
++ const struct scp_domain_data *data = &scp_domain_data[i];
++
++ pd_data->domains[i] = genpd;
++ scpd->scp = scp;
++
++ scpd->sta_mask = data->sta_mask;
++ scpd->ctl_addr = scp->base + data->ctl_offs;
++ scpd->sram_pdn_bits = data->sram_pdn_bits;
++ scpd->sram_pdn_ack_bits = data->sram_pdn_ack_bits;
++ scpd->bus_prot_mask = data->bus_prot_mask;
++ if (data->clk_id != MT8173_CLK_NONE)
++ scpd->clk = scp->clk[data->clk_id];
++
++ genpd->name = data->name;
++ genpd->power_off = scpsys_power_off;
++ genpd->power_on = scpsys_power_on;
++
++ /*
++ * Initially turn on all domains to make the domains usable
++ * with !CONFIG_PM and to get the hardware in sync with the
++ * software. The unused domains will be switched off during
++ * late_init time.
++ */
++ genpd->power_on(genpd);
++
++ pm_genpd_init(genpd, NULL, false);
++ }
++
++ /*
++ * We are not allowed to fail here since there is no way to unregister
++ * a power domain. Once registered above we have to keep the domains
++ * valid.
++ */
++
++ ret = pm_genpd_add_subdomain(pd_data->domains[MT8173_POWER_DOMAIN_MFG_ASYNC],
++ pd_data->domains[MT8173_POWER_DOMAIN_MFG_2D]);
++ if (ret && IS_ENABLED(CONFIG_PM))
++ dev_err(&pdev->dev, "Failed to add subdomain: %d\n", ret);
++
++ ret = pm_genpd_add_subdomain(pd_data->domains[MT8173_POWER_DOMAIN_MFG_2D],
++ pd_data->domains[MT8173_POWER_DOMAIN_MFG]);
++ if (ret && IS_ENABLED(CONFIG_PM))
++ dev_err(&pdev->dev, "Failed to add subdomain: %d\n", ret);
++
++ ret = of_genpd_add_provider_onecell(pdev->dev.of_node, pd_data);
++ if (ret)
++ dev_err(&pdev->dev, "Failed to add OF provider: %d\n", ret);
++
++ return 0;
++}
++
++static const struct of_device_id of_scpsys_match_tbl[] = {
++ {
++ .compatible = "mediatek,mt8173-scpsys",
++ }, {
++ /* sentinel */
++ }
++};
++
++static struct platform_driver scpsys_drv = {
++ .driver = {
++ .name = "mtk-scpsys",
++ .owner = THIS_MODULE,
++ .of_match_table = of_match_ptr(of_scpsys_match_tbl),
++ },
++};
++
++module_platform_driver_probe(scpsys_drv, scpsys_probe);
+diff --git a/include/dt-bindings/power/mt8173-power.h b/include/dt-bindings/power/mt8173-power.h
+new file mode 100644
+index 0000000..b34cee9
+--- /dev/null
++++ b/include/dt-bindings/power/mt8173-power.h
+@@ -0,0 +1,15 @@
++#ifndef _DT_BINDINGS_POWER_MT8183_POWER_H
++#define _DT_BINDINGS_POWER_MT8183_POWER_H
++
++#define MT8173_POWER_DOMAIN_VDEC 0
++#define MT8173_POWER_DOMAIN_VENC 1
++#define MT8173_POWER_DOMAIN_ISP 2
++#define MT8173_POWER_DOMAIN_MM 3
++#define MT8173_POWER_DOMAIN_VENC_LT 4
++#define MT8173_POWER_DOMAIN_AUDIO 5
++#define MT8173_POWER_DOMAIN_USB 6
++#define MT8173_POWER_DOMAIN_MFG_ASYNC 7
++#define MT8173_POWER_DOMAIN_MFG_2D 8
++#define MT8173_POWER_DOMAIN_MFG 9
++
++#endif /* _DT_BINDINGS_POWER_MT8183_POWER_H */
+--
+1.7.10.4
+
--- /dev/null
+From 87043a64dd5185dc076b3c3ab2e421b3a8c47798 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer@pengutronix.de>
+Date: Thu, 23 Apr 2015 10:35:43 +0200
+Subject: [PATCH 09/76] dt-bindings: ARM: Mediatek: Document devicetree
+ bindings for clock/reset controllers
+
+This adds the binding documentation for the apmixedsys, perisys and
+infracfg controllers found on Mediatek SoCs.
+
+Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
+---
+ .../bindings/arm/mediatek/mediatek,apmixedsys.txt | 23 +++++++++++++++
+ .../bindings/arm/mediatek/mediatek,infracfg.txt | 30 ++++++++++++++++++++
+ .../bindings/arm/mediatek/mediatek,pericfg.txt | 30 ++++++++++++++++++++
+ .../bindings/arm/mediatek/mediatek,topckgen.txt | 23 +++++++++++++++
+ 4 files changed, 106 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/arm/mediatek/mediatek,apmixedsys.txt
+ create mode 100644 Documentation/devicetree/bindings/arm/mediatek/mediatek,infracfg.txt
+ create mode 100644 Documentation/devicetree/bindings/arm/mediatek/mediatek,pericfg.txt
+ create mode 100644 Documentation/devicetree/bindings/arm/mediatek/mediatek,topckgen.txt
+
+diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,apmixedsys.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,apmixedsys.txt
+new file mode 100644
+index 0000000..5af6d73
+--- /dev/null
++++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,apmixedsys.txt
+@@ -0,0 +1,23 @@
++Mediatek apmixedsys controller
++==============================
++
++The Mediatek apmixedsys controller provides the PLLs to the system.
++
++Required Properties:
++
++- compatible: Should be:
++ - "mediatek,mt8135-apmixedsys"
++ - "mediatek,mt8173-apmixedsys"
++- #clock-cells: Must be 1
++
++The apmixedsys controller uses the common clk binding from
++Documentation/devicetree/bindings/clock/clock-bindings.txt
++The available clocks are defined in dt-bindings/clock/mt*-clk.h.
++
++Example:
++
++apmixedsys: apmixedsys@10209000 {
++ compatible = "mediatek,mt8173-apmixedsys";
++ reg = <0 0x10209000 0 0x1000>;
++ #clock-cells = <1>;
++};
+diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,infracfg.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,infracfg.txt
+new file mode 100644
+index 0000000..684da473
+--- /dev/null
++++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,infracfg.txt
+@@ -0,0 +1,30 @@
++Mediatek infracfg controller
++============================
++
++The Mediatek infracfg controller provides various clocks and reset
++outputs to the system.
++
++Required Properties:
++
++- compatible: Should be:
++ - "mediatek,mt8135-infracfg", "syscon"
++ - "mediatek,mt8173-infracfg", "syscon"
++- #clock-cells: Must be 1
++- #reset-cells: Must be 1
++
++The infracfg controller uses the common clk binding from
++Documentation/devicetree/bindings/clock/clock-bindings.txt
++The available clocks are defined in dt-bindings/clock/mt*-clk.h.
++Also it uses the common reset controller binding from
++Documentation/devicetree/bindings/reset/reset.txt.
++The available reset outputs are defined in
++dt-bindings/reset-controller/mt*-resets.h
++
++Example:
++
++infracfg: infracfg@10001000 {
++ compatible = "mediatek,mt8173-infracfg", "syscon";
++ reg = <0 0x10001000 0 0x1000>;
++ #clock-cells = <1>;
++ #reset-cells = <1>;
++};
+diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,pericfg.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,pericfg.txt
+new file mode 100644
+index 0000000..fdb45c6
+--- /dev/null
++++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,pericfg.txt
+@@ -0,0 +1,30 @@
++Mediatek pericfg controller
++===========================
++
++The Mediatek pericfg controller provides various clocks and reset
++outputs to the system.
++
++Required Properties:
++
++- compatible: Should be:
++ - "mediatek,mt8135-pericfg", "syscon"
++ - "mediatek,mt8173-pericfg", "syscon"
++- #clock-cells: Must be 1
++- #reset-cells: Must be 1
++
++The pericfg controller uses the common clk binding from
++Documentation/devicetree/bindings/clock/clock-bindings.txt
++The available clocks are defined in dt-bindings/clock/mt*-clk.h.
++Also it uses the common reset controller binding from
++Documentation/devicetree/bindings/reset/reset.txt.
++The available reset outputs are defined in
++dt-bindings/reset-controller/mt*-resets.h
++
++Example:
++
++pericfg: pericfg@10003000 {
++ compatible = "mediatek,mt8173-pericfg", "syscon";
++ reg = <0 0x10003000 0 0x1000>;
++ #clock-cells = <1>;
++ #reset-cells = <1>;
++};
+diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,topckgen.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,topckgen.txt
+new file mode 100644
+index 0000000..a425248
+--- /dev/null
++++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,topckgen.txt
+@@ -0,0 +1,23 @@
++Mediatek topckgen controller
++============================
++
++The Mediatek topckgen controller provides various clocks to the system.
++
++Required Properties:
++
++- compatible: Should be:
++ - "mediatek,mt8135-topckgen"
++ - "mediatek,mt8173-topckgen"
++- #clock-cells: Must be 1
++
++The topckgen controller uses the common clk binding from
++Documentation/devicetree/bindings/clock/clock-bindings.txt
++The available clocks are defined in dt-bindings/clock/mt*-clk.h.
++
++Example:
++
++topckgen: topckgen@10000000 {
++ compatible = "mediatek,mt8173-topckgen";
++ reg = <0 0x10000000 0 0x1000>;
++ #clock-cells = <1>;
++};
+--
+1.7.10.4
+
--- /dev/null
+From 29e6031548373b9e7ec0c17e85da6a4cf4fee7f5 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer@pengutronix.de>
+Date: Wed, 13 May 2015 10:52:29 +0200
+Subject: [PATCH 10/76] thermal: consistently use int for temperatures
+
+The thermal code uses int, long and unsigned long for temperatures
+in different places. Using an unsigned type limits the thermal framework
+to positive temperatures without need. 'long' is 64bit on several
+architectures which is not needed. Consistently use a plain 'int'
+for temperatures.
+
+Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
+---
+ drivers/acpi/thermal.c | 12 ++++-----
+ drivers/hwmon/lm75.c | 2 +-
+ drivers/hwmon/ntc_thermistor.c | 2 +-
+ drivers/hwmon/tmp102.c | 2 +-
+ drivers/input/touchscreen/sun4i-ts.c | 8 +++---
+ drivers/platform/x86/acerhdf.c | 9 +++----
+ drivers/power/power_supply_core.c | 2 +-
+ drivers/thermal/armada_thermal.c | 2 +-
+ drivers/thermal/db8500_thermal.c | 7 +++--
+ drivers/thermal/dove_thermal.c | 2 +-
+ drivers/thermal/fair_share.c | 2 +-
+ drivers/thermal/gov_bang_bang.c | 5 ++--
+ drivers/thermal/imx_thermal.c | 27 ++++++++++----------
+ .../thermal/int340x_thermal/int340x_thermal_zone.c | 10 ++++----
+ .../thermal/int340x_thermal/int340x_thermal_zone.h | 8 +++---
+ drivers/thermal/intel_soc_dts_thermal.c | 7 +++--
+ drivers/thermal/of-thermal.c | 14 +++++-----
+ drivers/thermal/rcar_thermal.c | 7 +++--
+ drivers/thermal/rockchip_thermal.c | 10 ++++----
+ drivers/thermal/samsung/exynos_tmu.c | 19 +++++++-------
+ drivers/thermal/spear_thermal.c | 2 +-
+ drivers/thermal/st/st_thermal.c | 5 ++--
+ drivers/thermal/step_wise.c | 4 +--
+ drivers/thermal/tegra_soctherm.c | 4 +--
+ drivers/thermal/thermal_core.c | 26 +++++++++----------
+ drivers/thermal/thermal_hwmon.c | 10 ++++----
+ drivers/thermal/ti-soc-thermal/ti-thermal-common.c | 10 ++++----
+ drivers/thermal/x86_pkg_temp_thermal.c | 10 ++++----
+ include/linux/thermal.h | 26 ++++++++-----------
+ 29 files changed, 120 insertions(+), 134 deletions(-)
+
+diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
+index d24fa19..68bff60 100644
+--- a/drivers/acpi/thermal.c
++++ b/drivers/acpi/thermal.c
+@@ -529,8 +529,7 @@ static void acpi_thermal_check(void *data)
+
+ /* sys I/F for generic thermal sysfs support */
+
+-static int thermal_get_temp(struct thermal_zone_device *thermal,
+- unsigned long *temp)
++static int thermal_get_temp(struct thermal_zone_device *thermal, int *temp)
+ {
+ struct acpi_thermal *tz = thermal->devdata;
+ int result;
+@@ -637,7 +636,7 @@ static int thermal_get_trip_type(struct thermal_zone_device *thermal,
+ }
+
+ static int thermal_get_trip_temp(struct thermal_zone_device *thermal,
+- int trip, unsigned long *temp)
++ int trip, int *temp)
+ {
+ struct acpi_thermal *tz = thermal->devdata;
+ int i;
+@@ -690,7 +689,8 @@ static int thermal_get_trip_temp(struct thermal_zone_device *thermal,
+ }
+
+ static int thermal_get_crit_temp(struct thermal_zone_device *thermal,
+- unsigned long *temperature) {
++ int *temperature)
++{
+ struct acpi_thermal *tz = thermal->devdata;
+
+ if (tz->trips.critical.flags.valid) {
+@@ -713,8 +713,8 @@ static int thermal_get_trend(struct thermal_zone_device *thermal,
+ return -EINVAL;
+
+ if (type == THERMAL_TRIP_ACTIVE) {
+- unsigned long trip_temp;
+- unsigned long temp = DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET(
++ int trip_temp;
++ int temp = DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET(
+ tz->temperature, tz->kelvin_offset);
+ if (thermal_get_trip_temp(thermal, trip, &trip_temp))
+ return -EINVAL;
+diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c
+index fe41d5a..e4e57bb 100644
+--- a/drivers/hwmon/lm75.c
++++ b/drivers/hwmon/lm75.c
+@@ -104,7 +104,7 @@ static inline long lm75_reg_to_mc(s16 temp, u8 resolution)
+
+ /* sysfs attributes for hwmon */
+
+-static int lm75_read_temp(void *dev, long *temp)
++static int lm75_read_temp(void *dev, int *temp)
+ {
+ struct lm75_data *data = lm75_update_device(dev);
+
+diff --git a/drivers/hwmon/ntc_thermistor.c b/drivers/hwmon/ntc_thermistor.c
+index 6880011..3d9eab9 100644
+--- a/drivers/hwmon/ntc_thermistor.c
++++ b/drivers/hwmon/ntc_thermistor.c
+@@ -439,7 +439,7 @@ static int ntc_thermistor_get_ohm(struct ntc_data *data)
+ return -EINVAL;
+ }
+
+-static int ntc_read_temp(void *dev, long *temp)
++static int ntc_read_temp(void *dev, int *temp)
+ {
+ struct ntc_data *data = dev_get_drvdata(dev);
+ int ohm;
+diff --git a/drivers/hwmon/tmp102.c b/drivers/hwmon/tmp102.c
+index 9da2735..6548262 100644
+--- a/drivers/hwmon/tmp102.c
++++ b/drivers/hwmon/tmp102.c
+@@ -98,7 +98,7 @@ static struct tmp102 *tmp102_update_device(struct device *dev)
+ return tmp102;
+ }
+
+-static int tmp102_read_temp(void *dev, long *temp)
++static int tmp102_read_temp(void *dev, int *temp)
+ {
+ struct tmp102 *tmp102 = tmp102_update_device(dev);
+
+diff --git a/drivers/input/touchscreen/sun4i-ts.c b/drivers/input/touchscreen/sun4i-ts.c
+index c011699..4857943 100644
+--- a/drivers/input/touchscreen/sun4i-ts.c
++++ b/drivers/input/touchscreen/sun4i-ts.c
+@@ -191,7 +191,7 @@ static void sun4i_ts_close(struct input_dev *dev)
+ writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC);
+ }
+
+-static int sun4i_get_temp(const struct sun4i_ts_data *ts, long *temp)
++static int sun4i_get_temp(const struct sun4i_ts_data *ts, int *temp)
+ {
+ /* No temp_data until the first irq */
+ if (ts->temp_data == -1)
+@@ -202,7 +202,7 @@ static int sun4i_get_temp(const struct sun4i_ts_data *ts, long *temp)
+ return 0;
+ }
+
+-static int sun4i_get_tz_temp(void *data, long *temp)
++static int sun4i_get_tz_temp(void *data, int *temp)
+ {
+ return sun4i_get_temp(data, temp);
+ }
+@@ -215,14 +215,14 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+ {
+ struct sun4i_ts_data *ts = dev_get_drvdata(dev);
+- long temp;
++ int temp;
+ int error;
+
+ error = sun4i_get_temp(ts, &temp);
+ if (error)
+ return error;
+
+- return sprintf(buf, "%ld\n", temp);
++ return sprintf(buf, "%d\n", temp);
+ }
+
+ static ssize_t show_temp_label(struct device *dev,
+diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c
+index 594c918..f2ce63c 100644
+--- a/drivers/platform/x86/acerhdf.c
++++ b/drivers/platform/x86/acerhdf.c
+@@ -346,8 +346,7 @@ static void acerhdf_check_param(struct thermal_zone_device *thermal)
+ * as late as the polling interval is since we can't do that in the respective
+ * accessors of the module parameters.
+ */
+-static int acerhdf_get_ec_temp(struct thermal_zone_device *thermal,
+- unsigned long *t)
++static int acerhdf_get_ec_temp(struct thermal_zone_device *thermal, int *t)
+ {
+ int temp, err = 0;
+
+@@ -452,7 +451,7 @@ static int acerhdf_get_trip_type(struct thermal_zone_device *thermal, int trip,
+ }
+
+ static int acerhdf_get_trip_hyst(struct thermal_zone_device *thermal, int trip,
+- unsigned long *temp)
++ int *temp)
+ {
+ if (trip != 0)
+ return -EINVAL;
+@@ -463,7 +462,7 @@ static int acerhdf_get_trip_hyst(struct thermal_zone_device *thermal, int trip,
+ }
+
+ static int acerhdf_get_trip_temp(struct thermal_zone_device *thermal, int trip,
+- unsigned long *temp)
++ int *temp)
+ {
+ if (trip == 0)
+ *temp = fanon;
+@@ -476,7 +475,7 @@ static int acerhdf_get_trip_temp(struct thermal_zone_device *thermal, int trip,
+ }
+
+ static int acerhdf_get_crit_temp(struct thermal_zone_device *thermal,
+- unsigned long *temperature)
++ int *temperature)
+ {
+ *temperature = ACERHDF_TEMP_CRIT;
+ return 0;
+diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c
+index 2ed4a4a..87e2fd1 100644
+--- a/drivers/power/power_supply_core.c
++++ b/drivers/power/power_supply_core.c
+@@ -492,7 +492,7 @@ EXPORT_SYMBOL_GPL(power_supply_unreg_notifier);
+
+ #ifdef CONFIG_THERMAL
+ static int power_supply_read_temp(struct thermal_zone_device *tzd,
+- unsigned long *temp)
++ int *temp)
+ {
+ struct power_supply *psy;
+ union power_supply_propval val;
+diff --git a/drivers/thermal/armada_thermal.c b/drivers/thermal/armada_thermal.c
+index 01255fd..26b8d32 100644
+--- a/drivers/thermal/armada_thermal.c
++++ b/drivers/thermal/armada_thermal.c
+@@ -155,7 +155,7 @@ static bool armada_is_valid(struct armada_thermal_priv *priv)
+ }
+
+ static int armada_get_temp(struct thermal_zone_device *thermal,
+- unsigned long *temp)
++ int *temp)
+ {
+ struct armada_thermal_priv *priv = thermal->devdata;
+ unsigned long reg;
+diff --git a/drivers/thermal/db8500_thermal.c b/drivers/thermal/db8500_thermal.c
+index 20adfbe..b3eca71 100644
+--- a/drivers/thermal/db8500_thermal.c
++++ b/drivers/thermal/db8500_thermal.c
+@@ -107,8 +107,7 @@ static int db8500_cdev_unbind(struct thermal_zone_device *thermal,
+ }
+
+ /* Callback to get current temperature */
+-static int db8500_sys_get_temp(struct thermal_zone_device *thermal,
+- unsigned long *temp)
++static int db8500_sys_get_temp(struct thermal_zone_device *thermal, int *temp)
+ {
+ struct db8500_thermal_zone *pzone = thermal->devdata;
+
+@@ -180,7 +179,7 @@ static int db8500_sys_get_trip_type(struct thermal_zone_device *thermal,
+
+ /* Callback to get trip point temperature */
+ static int db8500_sys_get_trip_temp(struct thermal_zone_device *thermal,
+- int trip, unsigned long *temp)
++ int trip, int *temp)
+ {
+ struct db8500_thermal_zone *pzone = thermal->devdata;
+ struct db8500_thsens_platform_data *ptrips = pzone->trip_tab;
+@@ -195,7 +194,7 @@ static int db8500_sys_get_trip_temp(struct thermal_zone_device *thermal,
+
+ /* Callback to get critical trip point temperature */
+ static int db8500_sys_get_crit_temp(struct thermal_zone_device *thermal,
+- unsigned long *temp)
++ int *temp)
+ {
+ struct db8500_thermal_zone *pzone = thermal->devdata;
+ struct db8500_thsens_platform_data *ptrips = pzone->trip_tab;
+diff --git a/drivers/thermal/dove_thermal.c b/drivers/thermal/dove_thermal.c
+index 09f6e30..a0bc9de 100644
+--- a/drivers/thermal/dove_thermal.c
++++ b/drivers/thermal/dove_thermal.c
+@@ -93,7 +93,7 @@ static int dove_init_sensor(const struct dove_thermal_priv *priv)
+ }
+
+ static int dove_get_temp(struct thermal_zone_device *thermal,
+- unsigned long *temp)
++ int *temp)
+ {
+ unsigned long reg;
+ struct dove_thermal_priv *priv = thermal->devdata;
+diff --git a/drivers/thermal/fair_share.c b/drivers/thermal/fair_share.c
+index 6e0a3fb..efad70e 100644
+--- a/drivers/thermal/fair_share.c
++++ b/drivers/thermal/fair_share.c
+@@ -34,7 +34,7 @@
+ static int get_trip_level(struct thermal_zone_device *tz)
+ {
+ int count = 0;
+- unsigned long trip_temp;
++ int trip_temp;
+ enum thermal_trip_type trip_type;
+
+ if (tz->trips == 0 || !tz->ops->get_trip_temp)
+diff --git a/drivers/thermal/gov_bang_bang.c b/drivers/thermal/gov_bang_bang.c
+index c5dd76b..70836c5 100644
+--- a/drivers/thermal/gov_bang_bang.c
++++ b/drivers/thermal/gov_bang_bang.c
+@@ -25,14 +25,13 @@
+
+ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip)
+ {
+- long trip_temp;
+- unsigned long trip_hyst;
++ int trip_temp, trip_hyst;
+ struct thermal_instance *instance;
+
+ tz->ops->get_trip_temp(tz, trip, &trip_temp);
+ tz->ops->get_trip_hyst(tz, trip, &trip_hyst);
+
+- dev_dbg(&tz->device, "Trip%d[temp=%ld]:temp=%d:hyst=%ld\n",
++ dev_dbg(&tz->device, "Trip%d[temp=%d]:temp=%d:hyst=%d\n",
+ trip, trip_temp, tz->temperature,
+ trip_hyst);
+
+diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c
+index 2ccbc07..f1424f0 100644
+--- a/drivers/thermal/imx_thermal.c
++++ b/drivers/thermal/imx_thermal.c
+@@ -98,10 +98,10 @@ struct imx_thermal_data {
+ enum thermal_device_mode mode;
+ struct regmap *tempmon;
+ u32 c1, c2; /* See formula in imx_get_sensor_data() */
+- unsigned long temp_passive;
+- unsigned long temp_critical;
+- unsigned long alarm_temp;
+- unsigned long last_temp;
++ int temp_passive;
++ int temp_critical;
++ int alarm_temp;
++ int last_temp;
+ bool irq_enabled;
+ int irq;
+ struct clk *thermal_clk;
+@@ -109,7 +109,7 @@ struct imx_thermal_data {
+ };
+
+ static void imx_set_panic_temp(struct imx_thermal_data *data,
+- signed long panic_temp)
++ int panic_temp)
+ {
+ struct regmap *map = data->tempmon;
+ int critical_value;
+@@ -121,7 +121,7 @@ static void imx_set_panic_temp(struct imx_thermal_data *data,
+ }
+
+ static void imx_set_alarm_temp(struct imx_thermal_data *data,
+- signed long alarm_temp)
++ int alarm_temp)
+ {
+ struct regmap *map = data->tempmon;
+ int alarm_value;
+@@ -133,7 +133,7 @@ static void imx_set_alarm_temp(struct imx_thermal_data *data,
+ TEMPSENSE0_ALARM_VALUE_SHIFT);
+ }
+
+-static int imx_get_temp(struct thermal_zone_device *tz, unsigned long *temp)
++static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
+ {
+ struct imx_thermal_data *data = tz->devdata;
+ struct regmap *map = data->tempmon;
+@@ -189,13 +189,13 @@ static int imx_get_temp(struct thermal_zone_device *tz, unsigned long *temp)
+ if (data->alarm_temp == data->temp_critical &&
+ *temp < data->temp_passive) {
+ imx_set_alarm_temp(data, data->temp_passive);
+- dev_dbg(&tz->device, "thermal alarm off: T < %lu\n",
++ dev_dbg(&tz->device, "thermal alarm off: T < %d\n",
+ data->alarm_temp / 1000);
+ }
+ }
+
+ if (*temp != data->last_temp) {
+- dev_dbg(&tz->device, "millicelsius: %ld\n", *temp);
++ dev_dbg(&tz->device, "millicelsius: %d\n", *temp);
+ data->last_temp = *temp;
+ }
+
+@@ -262,8 +262,7 @@ static int imx_get_trip_type(struct thermal_zone_device *tz, int trip,
+ return 0;
+ }
+
+-static int imx_get_crit_temp(struct thermal_zone_device *tz,
+- unsigned long *temp)
++static int imx_get_crit_temp(struct thermal_zone_device *tz, int *temp)
+ {
+ struct imx_thermal_data *data = tz->devdata;
+
+@@ -272,7 +271,7 @@ static int imx_get_crit_temp(struct thermal_zone_device *tz,
+ }
+
+ static int imx_get_trip_temp(struct thermal_zone_device *tz, int trip,
+- unsigned long *temp)
++ int *temp)
+ {
+ struct imx_thermal_data *data = tz->devdata;
+
+@@ -282,7 +281,7 @@ static int imx_get_trip_temp(struct thermal_zone_device *tz, int trip,
+ }
+
+ static int imx_set_trip_temp(struct thermal_zone_device *tz, int trip,
+- unsigned long temp)
++ int temp)
+ {
+ struct imx_thermal_data *data = tz->devdata;
+
+@@ -433,7 +432,7 @@ static irqreturn_t imx_thermal_alarm_irq_thread(int irq, void *dev)
+ {
+ struct imx_thermal_data *data = dev;
+
+- dev_dbg(&data->tz->device, "THERMAL ALARM: T > %lu\n",
++ dev_dbg(&data->tz->device, "THERMAL ALARM: T > %d\n",
+ data->alarm_temp / 1000);
+
+ thermal_zone_device_update(data->tz);
+diff --git a/drivers/thermal/int340x_thermal/int340x_thermal_zone.c b/drivers/thermal/int340x_thermal/int340x_thermal_zone.c
+index 1e25133..b9b2666 100644
+--- a/drivers/thermal/int340x_thermal/int340x_thermal_zone.c
++++ b/drivers/thermal/int340x_thermal/int340x_thermal_zone.c
+@@ -20,7 +20,7 @@
+ #include "int340x_thermal_zone.h"
+
+ static int int340x_thermal_get_zone_temp(struct thermal_zone_device *zone,
+- unsigned long *temp)
++ int *temp)
+ {
+ struct int34x_thermal_zone *d = zone->devdata;
+ unsigned long long tmp;
+@@ -49,7 +49,7 @@ static int int340x_thermal_get_zone_temp(struct thermal_zone_device *zone,
+ }
+
+ static int int340x_thermal_get_trip_temp(struct thermal_zone_device *zone,
+- int trip, unsigned long *temp)
++ int trip, int *temp)
+ {
+ struct int34x_thermal_zone *d = zone->devdata;
+ int i;
+@@ -114,7 +114,7 @@ static int int340x_thermal_get_trip_type(struct thermal_zone_device *zone,
+ }
+
+ static int int340x_thermal_set_trip_temp(struct thermal_zone_device *zone,
+- int trip, unsigned long temp)
++ int trip, int temp)
+ {
+ struct int34x_thermal_zone *d = zone->devdata;
+ acpi_status status;
+@@ -136,7 +136,7 @@ static int int340x_thermal_set_trip_temp(struct thermal_zone_device *zone,
+
+
+ static int int340x_thermal_get_trip_hyst(struct thermal_zone_device *zone,
+- int trip, unsigned long *temp)
++ int trip, int *temp)
+ {
+ struct int34x_thermal_zone *d = zone->devdata;
+ acpi_status status;
+@@ -163,7 +163,7 @@ static struct thermal_zone_device_ops int340x_thermal_zone_ops = {
+ };
+
+ static int int340x_thermal_get_trip_config(acpi_handle handle, char *name,
+- unsigned long *temp)
++ int *temp)
+ {
+ unsigned long long r;
+ acpi_status status;
+diff --git a/drivers/thermal/int340x_thermal/int340x_thermal_zone.h b/drivers/thermal/int340x_thermal/int340x_thermal_zone.h
+index 9f38ab7..aaadf72 100644
+--- a/drivers/thermal/int340x_thermal/int340x_thermal_zone.h
++++ b/drivers/thermal/int340x_thermal/int340x_thermal_zone.h
+@@ -21,7 +21,7 @@
+ #define INT340X_THERMAL_MAX_ACT_TRIP_COUNT 10
+
+ struct active_trip {
+- unsigned long temp;
++ int temp;
+ int id;
+ bool valid;
+ };
+@@ -31,11 +31,11 @@ struct int34x_thermal_zone {
+ struct active_trip act_trips[INT340X_THERMAL_MAX_ACT_TRIP_COUNT];
+ unsigned long *aux_trips;
+ int aux_trip_nr;
+- unsigned long psv_temp;
++ int psv_temp;
+ int psv_trip_id;
+- unsigned long crt_temp;
++ int crt_temp;
+ int crt_trip_id;
+- unsigned long hot_temp;
++ int hot_temp;
+ int hot_trip_id;
+ struct thermal_zone_device *zone;
+ struct thermal_zone_device_ops *override_ops;
+diff --git a/drivers/thermal/intel_soc_dts_thermal.c b/drivers/thermal/intel_soc_dts_thermal.c
+index 9013505..fd550b9 100644
+--- a/drivers/thermal/intel_soc_dts_thermal.c
++++ b/drivers/thermal/intel_soc_dts_thermal.c
+@@ -106,7 +106,7 @@ err_ret:
+ }
+
+ static int sys_get_trip_temp(struct thermal_zone_device *tzd,
+- int trip, unsigned long *temp)
++ int trip, int *temp)
+ {
+ int status;
+ u32 out;
+@@ -224,7 +224,7 @@ err_restore_ptps:
+ }
+
+ static int sys_set_trip_temp(struct thermal_zone_device *tzd, int trip,
+- unsigned long temp)
++ int temp)
+ {
+ struct soc_sensor_entry *aux_entry = tzd->devdata;
+ int status;
+@@ -250,8 +250,7 @@ static int sys_get_trip_type(struct thermal_zone_device *thermal,
+ return 0;
+ }
+
+-static int sys_get_curr_temp(struct thermal_zone_device *tzd,
+- unsigned long *temp)
++static int sys_get_curr_temp(struct thermal_zone_device *tzd, int *temp)
+ {
+ int status;
+ u32 out;
+diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
+index 668fb1b..03839df 100644
+--- a/drivers/thermal/of-thermal.c
++++ b/drivers/thermal/of-thermal.c
+@@ -87,7 +87,7 @@ struct __thermal_zone {
+ /*** DT thermal zone device callbacks ***/
+
+ static int of_thermal_get_temp(struct thermal_zone_device *tz,
+- unsigned long *temp)
++ int *temp)
+ {
+ struct __thermal_zone *data = tz->devdata;
+
+@@ -173,7 +173,7 @@ EXPORT_SYMBOL_GPL(of_thermal_get_trip_points);
+ * Return: zero on success, error code otherwise
+ */
+ static int of_thermal_set_emul_temp(struct thermal_zone_device *tz,
+- unsigned long temp)
++ int temp)
+ {
+ struct __thermal_zone *data = tz->devdata;
+
+@@ -306,7 +306,7 @@ static int of_thermal_get_trip_type(struct thermal_zone_device *tz, int trip,
+ }
+
+ static int of_thermal_get_trip_temp(struct thermal_zone_device *tz, int trip,
+- unsigned long *temp)
++ int *temp)
+ {
+ struct __thermal_zone *data = tz->devdata;
+
+@@ -319,7 +319,7 @@ static int of_thermal_get_trip_temp(struct thermal_zone_device *tz, int trip,
+ }
+
+ static int of_thermal_set_trip_temp(struct thermal_zone_device *tz, int trip,
+- unsigned long temp)
++ int temp)
+ {
+ struct __thermal_zone *data = tz->devdata;
+
+@@ -333,7 +333,7 @@ static int of_thermal_set_trip_temp(struct thermal_zone_device *tz, int trip,
+ }
+
+ static int of_thermal_get_trip_hyst(struct thermal_zone_device *tz, int trip,
+- unsigned long *hyst)
++ int *hyst)
+ {
+ struct __thermal_zone *data = tz->devdata;
+
+@@ -346,7 +346,7 @@ static int of_thermal_get_trip_hyst(struct thermal_zone_device *tz, int trip,
+ }
+
+ static int of_thermal_set_trip_hyst(struct thermal_zone_device *tz, int trip,
+- unsigned long hyst)
++ int hyst)
+ {
+ struct __thermal_zone *data = tz->devdata;
+
+@@ -360,7 +360,7 @@ static int of_thermal_set_trip_hyst(struct thermal_zone_device *tz, int trip,
+ }
+
+ static int of_thermal_get_crit_temp(struct thermal_zone_device *tz,
+- unsigned long *temp)
++ int *temp)
+ {
+ struct __thermal_zone *data = tz->devdata;
+ int i;
+diff --git a/drivers/thermal/rcar_thermal.c b/drivers/thermal/rcar_thermal.c
+index fe4e767..5d4ae7d 100644
+--- a/drivers/thermal/rcar_thermal.c
++++ b/drivers/thermal/rcar_thermal.c
+@@ -200,8 +200,7 @@ err_out_unlock:
+ return ret;
+ }
+
+-static int rcar_thermal_get_temp(struct thermal_zone_device *zone,
+- unsigned long *temp)
++static int rcar_thermal_get_temp(struct thermal_zone_device *zone, int *temp)
+ {
+ struct rcar_thermal_priv *priv = rcar_zone_to_priv(zone);
+
+@@ -235,7 +234,7 @@ static int rcar_thermal_get_trip_type(struct thermal_zone_device *zone,
+ }
+
+ static int rcar_thermal_get_trip_temp(struct thermal_zone_device *zone,
+- int trip, unsigned long *temp)
++ int trip, int *temp)
+ {
+ struct rcar_thermal_priv *priv = rcar_zone_to_priv(zone);
+ struct device *dev = rcar_priv_to_dev(priv);
+@@ -299,7 +298,7 @@ static void _rcar_thermal_irq_ctrl(struct rcar_thermal_priv *priv, int enable)
+ static void rcar_thermal_work(struct work_struct *work)
+ {
+ struct rcar_thermal_priv *priv;
+- unsigned long cctemp, nctemp;
++ int cctemp, nctemp;
+
+ priv = container_of(work, struct rcar_thermal_priv, work.work);
+
+diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c
+index cd8f5f93..c89ffb2 100644
+--- a/drivers/thermal/rockchip_thermal.c
++++ b/drivers/thermal/rockchip_thermal.c
+@@ -64,7 +64,7 @@ struct rockchip_tsadc_chip {
+ void (*control)(void __iomem *reg, bool on);
+
+ /* Per-sensor methods */
+- int (*get_temp)(int chn, void __iomem *reg, long *temp);
++ int (*get_temp)(int chn, void __iomem *reg, int *temp);
+ void (*set_tshut_temp)(int chn, void __iomem *reg, long temp);
+ void (*set_tshut_mode)(int chn, void __iomem *reg, enum tshut_mode m);
+ };
+@@ -191,7 +191,7 @@ static u32 rk_tsadcv2_temp_to_code(long temp)
+ return 0;
+ }
+
+-static long rk_tsadcv2_code_to_temp(u32 code)
++static int rk_tsadcv2_code_to_temp(u32 code)
+ {
+ unsigned int low = 0;
+ unsigned int high = ARRAY_SIZE(v2_code_table) - 1;
+@@ -277,7 +277,7 @@ static void rk_tsadcv2_control(void __iomem *regs, bool enable)
+ writel_relaxed(val, regs + TSADCV2_AUTO_CON);
+ }
+
+-static int rk_tsadcv2_get_temp(int chn, void __iomem *regs, long *temp)
++static int rk_tsadcv2_get_temp(int chn, void __iomem *regs, int *temp)
+ {
+ u32 val;
+
+@@ -366,7 +366,7 @@ static irqreturn_t rockchip_thermal_alarm_irq_thread(int irq, void *dev)
+ return IRQ_HANDLED;
+ }
+
+-static int rockchip_thermal_get_temp(void *_sensor, long *out_temp)
++static int rockchip_thermal_get_temp(void *_sensor, int *out_temp)
+ {
+ struct rockchip_thermal_sensor *sensor = _sensor;
+ struct rockchip_thermal_data *thermal = sensor->thermal;
+@@ -374,7 +374,7 @@ static int rockchip_thermal_get_temp(void *_sensor, long *out_temp)
+ int retval;
+
+ retval = tsadc->get_temp(sensor->id, thermal->regs, out_temp);
+- dev_dbg(&thermal->pdev->dev, "sensor %d - temp: %ld, retval: %d\n",
++ dev_dbg(&thermal->pdev->dev, "sensor %d - temp: %d, retval: %d\n",
+ sensor->id, *out_temp, retval);
+
+ return retval;
+diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
+index 1d30b09..29eaf4d 100644
+--- a/drivers/thermal/samsung/exynos_tmu.c
++++ b/drivers/thermal/samsung/exynos_tmu.c
+@@ -181,8 +181,7 @@ struct exynos_tmu_data {
+ int (*tmu_initialize)(struct platform_device *pdev);
+ void (*tmu_control)(struct platform_device *pdev, bool on);
+ int (*tmu_read)(struct exynos_tmu_data *data);
+- void (*tmu_set_emulation)(struct exynos_tmu_data *data,
+- unsigned long temp);
++ void (*tmu_set_emulation)(struct exynos_tmu_data *data, int temp);
+ void (*tmu_clear_irqs)(struct exynos_tmu_data *data);
+ };
+
+@@ -190,7 +189,7 @@ static void exynos_report_trigger(struct exynos_tmu_data *p)
+ {
+ char data[10], *envp[] = { data, NULL };
+ struct thermal_zone_device *tz = p->tzd;
+- unsigned long temp;
++ int temp;
+ unsigned int i;
+
+ if (!tz) {
+@@ -489,7 +488,7 @@ static int exynos5440_tmu_initialize(struct platform_device *pdev)
+ struct exynos_tmu_data *data = platform_get_drvdata(pdev);
+ unsigned int trim_info = 0, con, rising_threshold;
+ int ret = 0, threshold_code;
+- unsigned long crit_temp = 0;
++ int crit_temp = 0;
+
+ /*
+ * For exynos5440 soc triminfo value is swapped between TMU0 and
+@@ -542,7 +541,7 @@ static int exynos7_tmu_initialize(struct platform_device *pdev)
+ unsigned int status, trim_info;
+ unsigned int rising_threshold = 0, falling_threshold = 0;
+ int ret = 0, threshold_code, i;
+- unsigned long temp, temp_hist;
++ int temp, temp_hist;
+ unsigned int reg_off, bit_off;
+
+ status = readb(data->base + EXYNOS_TMU_REG_STATUS);
+@@ -713,7 +712,7 @@ static void exynos7_tmu_control(struct platform_device *pdev, bool on)
+ writel(con, data->base + EXYNOS_TMU_REG_CONTROL);
+ }
+
+-static int exynos_get_temp(void *p, long *temp)
++static int exynos_get_temp(void *p, int *temp)
+ {
+ struct exynos_tmu_data *data = p;
+
+@@ -733,7 +732,7 @@ static int exynos_get_temp(void *p, long *temp)
+
+ #ifdef CONFIG_THERMAL_EMULATION
+ static u32 get_emul_con_reg(struct exynos_tmu_data *data, unsigned int val,
+- unsigned long temp)
++ int temp)
+ {
+ if (temp) {
+ temp /= MCELSIUS;
+@@ -763,7 +762,7 @@ static u32 get_emul_con_reg(struct exynos_tmu_data *data, unsigned int val,
+ }
+
+ static void exynos4412_tmu_set_emulation(struct exynos_tmu_data *data,
+- unsigned long temp)
++ int temp)
+ {
+ unsigned int val;
+ u32 emul_con;
+@@ -781,7 +780,7 @@ static void exynos4412_tmu_set_emulation(struct exynos_tmu_data *data,
+ }
+
+ static void exynos5440_tmu_set_emulation(struct exynos_tmu_data *data,
+- unsigned long temp)
++ int temp)
+ {
+ unsigned int val;
+
+@@ -790,7 +789,7 @@ static void exynos5440_tmu_set_emulation(struct exynos_tmu_data *data,
+ writel(val, data->base + EXYNOS5440_TMU_S0_7_DEBUG);
+ }
+
+-static int exynos_tmu_set_emulation(void *drv_data, unsigned long temp)
++static int exynos_tmu_set_emulation(void *drv_data, int temp)
+ {
+ struct exynos_tmu_data *data = drv_data;
+ int ret = -EINVAL;
+diff --git a/drivers/thermal/spear_thermal.c b/drivers/thermal/spear_thermal.c
+index bddb717..534dd91 100644
+--- a/drivers/thermal/spear_thermal.c
++++ b/drivers/thermal/spear_thermal.c
+@@ -38,7 +38,7 @@ struct spear_thermal_dev {
+ };
+
+ static inline int thermal_get_temp(struct thermal_zone_device *thermal,
+- unsigned long *temp)
++ int *temp)
+ {
+ struct spear_thermal_dev *stdev = thermal->devdata;
+
+diff --git a/drivers/thermal/st/st_thermal.c b/drivers/thermal/st/st_thermal.c
+index 76c515d..44cbba9 100644
+--- a/drivers/thermal/st/st_thermal.c
++++ b/drivers/thermal/st/st_thermal.c
+@@ -111,8 +111,7 @@ static int st_thermal_calibration(struct st_thermal_sensor *sensor)
+ }
+
+ /* Callback to get temperature from HW*/
+-static int st_thermal_get_temp(struct thermal_zone_device *th,
+- unsigned long *temperature)
++static int st_thermal_get_temp(struct thermal_zone_device *th, int *temperature)
+ {
+ struct st_thermal_sensor *sensor = th->devdata;
+ struct device *dev = sensor->dev;
+@@ -159,7 +158,7 @@ static int st_thermal_get_trip_type(struct thermal_zone_device *th,
+ }
+
+ static int st_thermal_get_trip_temp(struct thermal_zone_device *th,
+- int trip, unsigned long *temp)
++ int trip, int *temp)
+ {
+ struct st_thermal_sensor *sensor = th->devdata;
+ struct device *dev = sensor->dev;
+diff --git a/drivers/thermal/step_wise.c b/drivers/thermal/step_wise.c
+index 5a0f12d..2f9f708 100644
+--- a/drivers/thermal/step_wise.c
++++ b/drivers/thermal/step_wise.c
+@@ -113,7 +113,7 @@ static void update_passive_instance(struct thermal_zone_device *tz,
+
+ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip)
+ {
+- long trip_temp;
++ int trip_temp;
+ enum thermal_trip_type trip_type;
+ enum thermal_trend trend;
+ struct thermal_instance *instance;
+@@ -135,7 +135,7 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip)
+ trace_thermal_zone_trip(tz, trip, trip_type);
+ }
+
+- dev_dbg(&tz->device, "Trip%d[type=%d,temp=%ld]:trend=%d,throttle=%d\n",
++ dev_dbg(&tz->device, "Trip%d[type=%d,temp=%d]:trend=%d,throttle=%d\n",
+ trip, trip_type, trip_temp, trend, throttle);
+
+ mutex_lock(&tz->lock);
+diff --git a/drivers/thermal/tegra_soctherm.c b/drivers/thermal/tegra_soctherm.c
+index 9197fc0..74ea576 100644
+--- a/drivers/thermal/tegra_soctherm.c
++++ b/drivers/thermal/tegra_soctherm.c
+@@ -293,7 +293,7 @@ static int enable_tsensor(struct tegra_soctherm *tegra,
+ * H denotes an addition of 0.5 Celsius and N denotes negation
+ * of the final value.
+ */
+-static long translate_temp(u16 val)
++static int translate_temp(u16 val)
+ {
+ long t;
+
+@@ -306,7 +306,7 @@ static long translate_temp(u16 val)
+ return t;
+ }
+
+-static int tegra_thermctl_get_temp(void *data, long *out_temp)
++static int tegra_thermctl_get_temp(void *data, int *out_temp)
+ {
+ struct tegra_thermctl_zone *zone = data;
+ u32 val;
+diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
+index 4108db7..62cc82a 100644
+--- a/drivers/thermal/thermal_core.c
++++ b/drivers/thermal/thermal_core.c
+@@ -363,7 +363,7 @@ static void handle_non_critical_trips(struct thermal_zone_device *tz,
+ static void handle_critical_trips(struct thermal_zone_device *tz,
+ int trip, enum thermal_trip_type trip_type)
+ {
+- long trip_temp;
++ int trip_temp;
+
+ tz->ops->get_trip_temp(tz, trip, &trip_temp);
+
+@@ -411,12 +411,12 @@ static void handle_thermal_trip(struct thermal_zone_device *tz, int trip)
+ *
+ * Return: On success returns 0, an error code otherwise
+ */
+-int thermal_zone_get_temp(struct thermal_zone_device *tz, unsigned long *temp)
++int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp)
+ {
+ int ret = -EINVAL;
+ #ifdef CONFIG_THERMAL_EMULATION
+ int count;
+- unsigned long crit_temp = -1UL;
++ int crit_temp = INT_MAX;
+ enum thermal_trip_type type;
+ #endif
+
+@@ -453,8 +453,7 @@ EXPORT_SYMBOL_GPL(thermal_zone_get_temp);
+
+ static void update_temperature(struct thermal_zone_device *tz)
+ {
+- long temp;
+- int ret;
++ int temp, ret;
+
+ ret = thermal_zone_get_temp(tz, &temp);
+ if (ret) {
+@@ -514,15 +513,14 @@ static ssize_t
+ temp_show(struct device *dev, struct device_attribute *attr, char *buf)
+ {
+ struct thermal_zone_device *tz = to_thermal_zone(dev);
+- long temperature;
+- int ret;
++ int temperature, ret;
+
+ ret = thermal_zone_get_temp(tz, &temperature);
+
+ if (ret)
+ return ret;
+
+- return sprintf(buf, "%ld\n", temperature);
++ return sprintf(buf, "%d\n", temperature);
+ }
+
+ static ssize_t
+@@ -626,7 +624,7 @@ trip_point_temp_show(struct device *dev, struct device_attribute *attr,
+ {
+ struct thermal_zone_device *tz = to_thermal_zone(dev);
+ int trip, ret;
+- long temperature;
++ int temperature;
+
+ if (!tz->ops->get_trip_temp)
+ return -EPERM;
+@@ -639,7 +637,7 @@ trip_point_temp_show(struct device *dev, struct device_attribute *attr,
+ if (ret)
+ return ret;
+
+- return sprintf(buf, "%ld\n", temperature);
++ return sprintf(buf, "%d\n", temperature);
+ }
+
+ static ssize_t
+@@ -648,7 +646,7 @@ trip_point_hyst_store(struct device *dev, struct device_attribute *attr,
+ {
+ struct thermal_zone_device *tz = to_thermal_zone(dev);
+ int trip, ret;
+- unsigned long temperature;
++ int temperature;
+
+ if (!tz->ops->set_trip_hyst)
+ return -EPERM;
+@@ -656,7 +654,7 @@ trip_point_hyst_store(struct device *dev, struct device_attribute *attr,
+ if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip))
+ return -EINVAL;
+
+- if (kstrtoul(buf, 10, &temperature))
++ if (kstrtoint(buf, 10, &temperature))
+ return -EINVAL;
+
+ /*
+@@ -675,7 +673,7 @@ trip_point_hyst_show(struct device *dev, struct device_attribute *attr,
+ {
+ struct thermal_zone_device *tz = to_thermal_zone(dev);
+ int trip, ret;
+- unsigned long temperature;
++ int temperature;
+
+ if (!tz->ops->get_trip_hyst)
+ return -EPERM;
+@@ -685,7 +683,7 @@ trip_point_hyst_show(struct device *dev, struct device_attribute *attr,
+
+ ret = tz->ops->get_trip_hyst(tz, trip, &temperature);
+
+- return ret ? ret : sprintf(buf, "%ld\n", temperature);
++ return ret ? ret : sprintf(buf, "%d\n", temperature);
+ }
+
+ static ssize_t
+diff --git a/drivers/thermal/thermal_hwmon.c b/drivers/thermal/thermal_hwmon.c
+index 1967bee..06fd2ed9 100644
+--- a/drivers/thermal/thermal_hwmon.c
++++ b/drivers/thermal/thermal_hwmon.c
+@@ -69,7 +69,7 @@ static DEVICE_ATTR(name, 0444, name_show, NULL);
+ static ssize_t
+ temp_input_show(struct device *dev, struct device_attribute *attr, char *buf)
+ {
+- long temperature;
++ int temperature;
+ int ret;
+ struct thermal_hwmon_attr *hwmon_attr
+ = container_of(attr, struct thermal_hwmon_attr, attr);
+@@ -83,7 +83,7 @@ temp_input_show(struct device *dev, struct device_attribute *attr, char *buf)
+ if (ret)
+ return ret;
+
+- return sprintf(buf, "%ld\n", temperature);
++ return sprintf(buf, "%d\n", temperature);
+ }
+
+ static ssize_t
+@@ -95,14 +95,14 @@ temp_crit_show(struct device *dev, struct device_attribute *attr, char *buf)
+ = container_of(hwmon_attr, struct thermal_hwmon_temp,
+ temp_crit);
+ struct thermal_zone_device *tz = temp->tz;
+- long temperature;
++ int temperature;
+ int ret;
+
+ ret = tz->ops->get_trip_temp(tz, 0, &temperature);
+ if (ret)
+ return ret;
+
+- return sprintf(buf, "%ld\n", temperature);
++ return sprintf(buf, "%d\n", temperature);
+ }
+
+
+@@ -142,7 +142,7 @@ thermal_hwmon_lookup_temp(const struct thermal_hwmon_device *hwmon,
+
+ static bool thermal_zone_crit_temp_valid(struct thermal_zone_device *tz)
+ {
+- unsigned long temp;
++ int temp;
+ return tz->ops->get_crit_temp && !tz->ops->get_crit_temp(tz, &temp);
+ }
+
+diff --git a/drivers/thermal/ti-soc-thermal/ti-thermal-common.c b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
+index a38c175..d3a42bf 100644
+--- a/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
++++ b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
+@@ -76,14 +76,14 @@ static inline int ti_thermal_hotspot_temperature(int t, int s, int c)
+
+ /* thermal zone ops */
+ /* Get temperature callback function for thermal zone*/
+-static inline int __ti_thermal_get_temp(void *devdata, long *temp)
++static inline int __ti_thermal_get_temp(void *devdata, int *temp)
+ {
+ struct thermal_zone_device *pcb_tz = NULL;
+ struct ti_thermal_data *data = devdata;
+ struct ti_bandgap *bgp;
+ const struct ti_temp_sensor *s;
+ int ret, tmp, slope, constant;
+- unsigned long pcb_temp;
++ int pcb_temp;
+
+ if (!data)
+ return 0;
+@@ -119,7 +119,7 @@ static inline int __ti_thermal_get_temp(void *devdata, long *temp)
+ }
+
+ static inline int ti_thermal_get_temp(struct thermal_zone_device *thermal,
+- unsigned long *temp)
++ int *temp)
+ {
+ struct ti_thermal_data *data = thermal->devdata;
+
+@@ -228,7 +228,7 @@ static int ti_thermal_get_trip_type(struct thermal_zone_device *thermal,
+
+ /* Get trip temperature callback functions for thermal zone */
+ static int ti_thermal_get_trip_temp(struct thermal_zone_device *thermal,
+- int trip, unsigned long *temp)
++ int trip, int *temp)
+ {
+ if (!ti_thermal_is_valid_trip(trip))
+ return -EINVAL;
+@@ -279,7 +279,7 @@ static int ti_thermal_get_trend(struct thermal_zone_device *thermal,
+
+ /* Get critical temperature callback functions for thermal zone */
+ static int ti_thermal_get_crit_temp(struct thermal_zone_device *thermal,
+- unsigned long *temp)
++ int *temp)
+ {
+ /* shutdown zone */
+ return ti_thermal_get_trip_temp(thermal, OMAP_TRIP_NUMBER - 1, temp);
+diff --git a/drivers/thermal/x86_pkg_temp_thermal.c b/drivers/thermal/x86_pkg_temp_thermal.c
+index 9ea3d9d..054c6d45 100644
+--- a/drivers/thermal/x86_pkg_temp_thermal.c
++++ b/drivers/thermal/x86_pkg_temp_thermal.c
+@@ -164,7 +164,7 @@ err_ret:
+ return err;
+ }
+
+-static int sys_get_curr_temp(struct thermal_zone_device *tzd, unsigned long *temp)
++static int sys_get_curr_temp(struct thermal_zone_device *tzd, int *temp)
+ {
+ u32 eax, edx;
+ struct phy_dev_entry *phy_dev_entry;
+@@ -175,7 +175,7 @@ static int sys_get_curr_temp(struct thermal_zone_device *tzd, unsigned long *tem
+ if (eax & 0x80000000) {
+ *temp = phy_dev_entry->tj_max -
+ ((eax >> 16) & 0x7f) * 1000;
+- pr_debug("sys_get_curr_temp %ld\n", *temp);
++ pr_debug("sys_get_curr_temp %d\n", *temp);
+ return 0;
+ }
+
+@@ -183,7 +183,7 @@ static int sys_get_curr_temp(struct thermal_zone_device *tzd, unsigned long *tem
+ }
+
+ static int sys_get_trip_temp(struct thermal_zone_device *tzd,
+- int trip, unsigned long *temp)
++ int trip, int *temp)
+ {
+ u32 eax, edx;
+ struct phy_dev_entry *phy_dev_entry;
+@@ -214,13 +214,13 @@ static int sys_get_trip_temp(struct thermal_zone_device *tzd,
+ *temp = phy_dev_entry->tj_max - thres_reg_value * 1000;
+ else
+ *temp = 0;
+- pr_debug("sys_get_trip_temp %ld\n", *temp);
++ pr_debug("sys_get_trip_temp %d\n", *temp);
+
+ return 0;
+ }
+
+ static int sys_set_trip_temp(struct thermal_zone_device *tzd, int trip,
+- unsigned long temp)
++ int temp)
+ {
+ u32 l, h;
+ struct phy_dev_entry *phy_dev_entry;
+diff --git a/include/linux/thermal.h b/include/linux/thermal.h
+index 5eac316..e9f2863 100644
+--- a/include/linux/thermal.h
++++ b/include/linux/thermal.h
+@@ -86,23 +86,19 @@ struct thermal_zone_device_ops {
+ struct thermal_cooling_device *);
+ int (*unbind) (struct thermal_zone_device *,
+ struct thermal_cooling_device *);
+- int (*get_temp) (struct thermal_zone_device *, unsigned long *);
++ int (*get_temp) (struct thermal_zone_device *, int *);
+ int (*get_mode) (struct thermal_zone_device *,
+ enum thermal_device_mode *);
+ int (*set_mode) (struct thermal_zone_device *,
+ enum thermal_device_mode);
+ int (*get_trip_type) (struct thermal_zone_device *, int,
+ enum thermal_trip_type *);
+- int (*get_trip_temp) (struct thermal_zone_device *, int,
+- unsigned long *);
+- int (*set_trip_temp) (struct thermal_zone_device *, int,
+- unsigned long);
+- int (*get_trip_hyst) (struct thermal_zone_device *, int,
+- unsigned long *);
+- int (*set_trip_hyst) (struct thermal_zone_device *, int,
+- unsigned long);
+- int (*get_crit_temp) (struct thermal_zone_device *, unsigned long *);
+- int (*set_emul_temp) (struct thermal_zone_device *, unsigned long);
++ int (*get_trip_temp) (struct thermal_zone_device *, int, int *);
++ int (*set_trip_temp) (struct thermal_zone_device *, int, int);
++ int (*get_trip_hyst) (struct thermal_zone_device *, int, int *);
++ int (*set_trip_hyst) (struct thermal_zone_device *, int, int);
++ int (*get_crit_temp) (struct thermal_zone_device *, int *);
++ int (*set_emul_temp) (struct thermal_zone_device *, int);
+ int (*get_trend) (struct thermal_zone_device *, int,
+ enum thermal_trend *);
+ int (*notify) (struct thermal_zone_device *, int,
+@@ -272,9 +268,9 @@ struct thermal_genl_event {
+ * temperature.
+ */
+ struct thermal_zone_of_device_ops {
+- int (*get_temp)(void *, long *);
++ int (*get_temp)(void *, int *);
+ int (*get_trend)(void *, long *);
+- int (*set_emul_temp)(void *, unsigned long);
++ int (*set_emul_temp)(void *, int);
+ };
+
+ /**
+@@ -335,7 +331,7 @@ thermal_of_cooling_device_register(struct device_node *np, char *, void *,
+ const struct thermal_cooling_device_ops *);
+ void thermal_cooling_device_unregister(struct thermal_cooling_device *);
+ struct thermal_zone_device *thermal_zone_get_zone_by_name(const char *name);
+-int thermal_zone_get_temp(struct thermal_zone_device *tz, unsigned long *temp);
++int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp);
+
+ int get_tz_trend(struct thermal_zone_device *, int);
+ struct thermal_instance *get_thermal_instance(struct thermal_zone_device *,
+@@ -378,7 +374,7 @@ static inline struct thermal_zone_device *thermal_zone_get_zone_by_name(
+ const char *name)
+ { return ERR_PTR(-ENODEV); }
+ static inline int thermal_zone_get_temp(
+- struct thermal_zone_device *tz, unsigned long *temp)
++ struct thermal_zone_device *tz, int *temp)
+ { return -ENODEV; }
+ static inline int get_tz_trend(struct thermal_zone_device *tz, int trip)
+ { return -ENODEV; }
+--
+1.7.10.4
+
--- /dev/null
+From a2214b951a1102ad2a2a72b6ae6e71c148f8249f Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer@pengutronix.de>
+Date: Wed, 13 May 2015 10:52:30 +0200
+Subject: [PATCH 11/76] thermal: trivial: fix typo in comment
+
+Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
+Acked-by: Eduardo Valentin <edubezval@gmail.com>
+---
+ drivers/thermal/thermal_core.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
+index 62cc82a..244784f 100644
+--- a/drivers/thermal/thermal_core.c
++++ b/drivers/thermal/thermal_core.c
+@@ -402,7 +402,7 @@ static void handle_thermal_trip(struct thermal_zone_device *tz, int trip)
+ }
+
+ /**
+- * thermal_zone_get_temp() - returns its the temperature of thermal zone
++ * thermal_zone_get_temp() - returns the temperature of a thermal zone
+ * @tz: a valid pointer to a struct thermal_zone_device
+ * @temp: a valid pointer to where to store the resulting temperature.
+ *
+--
+1.7.10.4
+
--- /dev/null
+From 41adcc8cf217dfb4b70c2da061e70034b3c9add0 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer@pengutronix.de>
+Date: Wed, 13 May 2015 10:52:31 +0200
+Subject: [PATCH 12/76] thermal: remove useless call to
+ thermal_zone_device_set_polling
+
+When the thermal zone has no get_temp callback then thermal_zone_device_register()
+calls thermal_zone_device_set_polling() with a polling delay of 0. This
+only cancels the poll_queue. Since the poll_queue hasn't been scheduled this
+is a no-op. Remove it.
+
+Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
+Acked-by: Eduardo Valentin <edubezval@gmail.com>
+---
+ drivers/thermal/thermal_core.c | 3 ---
+ 1 file changed, 3 deletions(-)
+
+diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
+index 244784f..1b68d20 100644
+--- a/drivers/thermal/thermal_core.c
++++ b/drivers/thermal/thermal_core.c
+@@ -1571,9 +1571,6 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type,
+
+ INIT_DELAYED_WORK(&(tz->poll_queue), thermal_zone_device_check);
+
+- if (!tz->ops->get_temp)
+- thermal_zone_device_set_polling(tz, 0);
+-
+ thermal_zone_device_update(tz);
+
+ return tz;
+--
+1.7.10.4
+
--- /dev/null
+From bddcae2b66a23bfb6d381d089b0b862235480a9b Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer@pengutronix.de>
+Date: Wed, 13 May 2015 10:52:32 +0200
+Subject: [PATCH 13/76] thermal: Use IS_ENABLED instead of #ifdef
+
+Use IS_ENABLED(CONFIG_THERMAL_EMULATION) to make the code more readable
+and to get rid of the addtional #ifdef around the variable definitions
+in thermal_zone_get_temp().
+
+Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
+---
+ drivers/thermal/thermal_core.c | 45 +++++++++++++++++-----------------------
+ 1 file changed, 19 insertions(+), 26 deletions(-)
+
+diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
+index 1b68d20..3e0fe55 100644
+--- a/drivers/thermal/thermal_core.c
++++ b/drivers/thermal/thermal_core.c
+@@ -414,11 +414,9 @@ static void handle_thermal_trip(struct thermal_zone_device *tz, int trip)
+ int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp)
+ {
+ int ret = -EINVAL;
+-#ifdef CONFIG_THERMAL_EMULATION
+ int count;
+ int crit_temp = INT_MAX;
+ enum thermal_trip_type type;
+-#endif
+
+ if (!tz || IS_ERR(tz) || !tz->ops->get_temp)
+ goto exit;
+@@ -426,25 +424,21 @@ int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp)
+ mutex_lock(&tz->lock);
+
+ ret = tz->ops->get_temp(tz, temp);
+-#ifdef CONFIG_THERMAL_EMULATION
+- if (!tz->emul_temperature)
+- goto skip_emul;
+-
+- for (count = 0; count < tz->trips; count++) {
+- ret = tz->ops->get_trip_type(tz, count, &type);
+- if (!ret && type == THERMAL_TRIP_CRITICAL) {
+- ret = tz->ops->get_trip_temp(tz, count, &crit_temp);
+- break;
+- }
+- }
+
+- if (ret)
+- goto skip_emul;
++ if (IS_ENABLED(CONFIG_THERMAL_EMULATION) && tz->emul_temperature) {
++ for (count = 0; count < tz->trips; count++) {
++ ret = tz->ops->get_trip_type(tz, count, &type);
++ if (!ret && type == THERMAL_TRIP_CRITICAL) {
++ ret = tz->ops->get_trip_temp(tz, count,
++ &crit_temp);
++ break;
++ }
++ }
+
+- if (*temp < crit_temp)
+- *temp = tz->emul_temperature;
+-skip_emul:
+-#endif
++ if (!ret && *temp < crit_temp)
++ *temp = tz->emul_temperature;
++ }
++
+ mutex_unlock(&tz->lock);
+ exit:
+ return ret;
+@@ -780,7 +774,6 @@ policy_show(struct device *dev, struct device_attribute *devattr, char *buf)
+ return sprintf(buf, "%s\n", tz->governor->name);
+ }
+
+-#ifdef CONFIG_THERMAL_EMULATION
+ static ssize_t
+ emul_temp_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+@@ -806,7 +799,6 @@ emul_temp_store(struct device *dev, struct device_attribute *attr,
+ return ret ? ret : count;
+ }
+ static DEVICE_ATTR(emul_temp, S_IWUSR, NULL, emul_temp_store);
+-#endif/*CONFIG_THERMAL_EMULATION*/
+
+ static DEVICE_ATTR(type, 0444, type_show, NULL);
+ static DEVICE_ATTR(temp, 0444, temp_show, NULL);
+@@ -1536,11 +1528,12 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type,
+ goto unregister;
+ }
+
+-#ifdef CONFIG_THERMAL_EMULATION
+- result = device_create_file(&tz->device, &dev_attr_emul_temp);
+- if (result)
+- goto unregister;
+-#endif
++ if (IS_ENABLED(CONFIG_THERMAL_EMULATION)) {
++ result = device_create_file(&tz->device, &dev_attr_emul_temp);
++ if (result)
++ goto unregister;
++ }
++
+ /* Create policy attribute */
+ result = device_create_file(&tz->device, &dev_attr_policy);
+ if (result)
+--
+1.7.10.4
+
--- /dev/null
+From 18f50eae474edc716b01959fad6898c8553b131c Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer@pengutronix.de>
+Date: Wed, 13 May 2015 10:52:33 +0200
+Subject: [PATCH 14/76] thermal: Add comment explaining test for critical
+ temperature
+
+The code testing if a temperature should be emulated or not is
+not obvious. Add a comment explaining why this test is done.
+
+Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
+Reviewed-by: Mikko Perttunen <mperttunen@nvidia.com>
+---
+ drivers/thermal/thermal_core.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
+index 3e0fe55..e204deb 100644
+--- a/drivers/thermal/thermal_core.c
++++ b/drivers/thermal/thermal_core.c
+@@ -435,6 +435,11 @@ int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp)
+ }
+ }
+
++ /*
++ * Only allow emulating a temperature when the real temperature
++ * is below the critical temperature so that the emulation code
++ * cannot hide critical conditions.
++ */
+ if (!ret && *temp < crit_temp)
+ *temp = tz->emul_temperature;
+ }
+--
+1.7.10.4
+
--- /dev/null
+From 0b729a98127ef045096edf20dfe5c4eadac21d44 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer@pengutronix.de>
+Date: Wed, 13 May 2015 10:52:34 +0200
+Subject: [PATCH 15/76] thermal: inline only once used function
+
+Inline update_temperature into its only caller to make the code
+more readable.
+
+Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
+Reviewed-by: Mikko Perttunen <mperttunen@nvidia.com>
+---
+ drivers/thermal/thermal_core.c | 17 +++++------------
+ 1 file changed, 5 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
+index e204deb..19da022 100644
+--- a/drivers/thermal/thermal_core.c
++++ b/drivers/thermal/thermal_core.c
+@@ -450,9 +450,12 @@ exit:
+ }
+ EXPORT_SYMBOL_GPL(thermal_zone_get_temp);
+
+-static void update_temperature(struct thermal_zone_device *tz)
++void thermal_zone_device_update(struct thermal_zone_device *tz)
+ {
+- int temp, ret;
++ int temp, ret, count;
++
++ if (!tz->ops->get_temp)
++ return;
+
+ ret = thermal_zone_get_temp(tz, &temp);
+ if (ret) {
+@@ -471,16 +474,6 @@ static void update_temperature(struct thermal_zone_device *tz)
+ trace_thermal_temperature(tz);
+ dev_dbg(&tz->device, "last_temperature=%d, current_temperature=%d\n",
+ tz->last_temperature, tz->temperature);
+-}
+-
+-void thermal_zone_device_update(struct thermal_zone_device *tz)
+-{
+- int count;
+-
+- if (!tz->ops->get_temp)
+- return;
+-
+- update_temperature(tz);
+
+ for (count = 0; count < tz->trips; count++)
+ handle_thermal_trip(tz, count);
+--
+1.7.10.4
+
--- /dev/null
+From 5da86f6a2b4c2c318e153649dc8fd34fe73f8292 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer@pengutronix.de>
+Date: Wed, 13 May 2015 10:52:35 +0200
+Subject: [PATCH 16/76] thermal: streamline get_trend callbacks
+
+The .get_trend callback in struct thermal_zone_device_ops has the prototype:
+
+ int (*get_trend) (struct thermal_zone_device *, int,
+ enum thermal_trend *);
+
+whereas the .get_trend callback in struct thermal_zone_of_device_ops has:
+
+ int (*get_trend)(void *, long *);
+
+Streamline both prototypes and add the trip argument to the OF callback
+aswell and use enum thermal_trend * instead of an integer pointer.
+
+While the OF prototype may be the better one, this should be decided at
+framework level and not on OF level.
+
+Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
+---
+ drivers/thermal/of-thermal.c | 11 +--------
+ drivers/thermal/ti-soc-thermal/ti-thermal-common.c | 25 +++++++-------------
+ include/linux/thermal.h | 2 +-
+ 3 files changed, 10 insertions(+), 28 deletions(-)
+
+diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
+index 03839df..c84404d 100644
+--- a/drivers/thermal/of-thermal.c
++++ b/drivers/thermal/of-thermal.c
+@@ -187,24 +187,15 @@ static int of_thermal_get_trend(struct thermal_zone_device *tz, int trip,
+ enum thermal_trend *trend)
+ {
+ struct __thermal_zone *data = tz->devdata;
+- long dev_trend;
+ int r;
+
+ if (!data->ops->get_trend)
+ return -EINVAL;
+
+- r = data->ops->get_trend(data->sensor_data, &dev_trend);
++ r = data->ops->get_trend(data->sensor_data, trip, trend);
+ if (r)
+ return r;
+
+- /* TODO: These intervals might have some thresholds, but in core code */
+- if (dev_trend > 0)
+- *trend = THERMAL_TREND_RAISING;
+- else if (dev_trend < 0)
+- *trend = THERMAL_TREND_DROPPING;
+- else
+- *trend = THERMAL_TREND_STABLE;
+-
+ return 0;
+ }
+
+diff --git a/drivers/thermal/ti-soc-thermal/ti-thermal-common.c b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
+index d3a42bf..ade78eb 100644
+--- a/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
++++ b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
+@@ -238,7 +238,7 @@ static int ti_thermal_get_trip_temp(struct thermal_zone_device *thermal,
+ return 0;
+ }
+
+-static int __ti_thermal_get_trend(void *p, long *trend)
++static int __ti_thermal_get_trend(void *p, int trip, enum thermal_trend *trend)
+ {
+ struct ti_thermal_data *data = p;
+ struct ti_bandgap *bgp;
+@@ -251,22 +251,6 @@ static int __ti_thermal_get_trend(void *p, long *trend)
+ if (ret)
+ return ret;
+
+- *trend = tr;
+-
+- return 0;
+-}
+-
+-/* Get the temperature trend callback functions for thermal zone */
+-static int ti_thermal_get_trend(struct thermal_zone_device *thermal,
+- int trip, enum thermal_trend *trend)
+-{
+- int ret;
+- long tr;
+-
+- ret = __ti_thermal_get_trend(thermal->devdata, &tr);
+- if (ret)
+- return ret;
+-
+ if (tr > 0)
+ *trend = THERMAL_TREND_RAISING;
+ else if (tr < 0)
+@@ -277,6 +261,13 @@ static int ti_thermal_get_trend(struct thermal_zone_device *thermal,
+ return 0;
+ }
+
++/* Get the temperature trend callback functions for thermal zone */
++static int ti_thermal_get_trend(struct thermal_zone_device *thermal,
++ int trip, enum thermal_trend *trend)
++{
++ return __ti_thermal_get_trend(thermal->devdata, trip, trend);
++}
++
+ /* Get critical temperature callback functions for thermal zone */
+ static int ti_thermal_get_crit_temp(struct thermal_zone_device *thermal,
+ int *temp)
+diff --git a/include/linux/thermal.h b/include/linux/thermal.h
+index e9f2863..5c6a589 100644
+--- a/include/linux/thermal.h
++++ b/include/linux/thermal.h
+@@ -269,7 +269,7 @@ struct thermal_genl_event {
+ */
+ struct thermal_zone_of_device_ops {
+ int (*get_temp)(void *, int *);
+- int (*get_trend)(void *, long *);
++ int (*get_trend)(void *, int, enum thermal_trend *);
+ int (*set_emul_temp)(void *, int);
+ };
+
+--
+1.7.10.4
+
--- /dev/null
+From 5b622cb2d6ff44b1fb0750beee61f93f2c00548a Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer@pengutronix.de>
+Date: Wed, 13 May 2015 10:52:36 +0200
+Subject: [PATCH 17/76] thermal: Allow sensor ops to fail with -ENOSYS
+
+The thermal core uses the existence of the .get_temp, .get_trend and
+.set_emul_temp to detect whether this operation exists and should be
+used or whether it should be emulated in software. This makes problems
+for of-thermal which has to modify the struct thermal_zone_device_ops
+during runtime whenever a sensor is registered or unregistered.
+
+Let the core test for -ENOSYS from these callbacks and treat it like
+if the callbacks were not present.
+
+This allows of-thermal to always set the sensor related callbacks and
+to make struct thermal_zone_device_ops const again.
+
+Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
+---
+ drivers/thermal/thermal_core.c | 24 +++++++++++++++++-------
+ 1 file changed, 17 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
+index 19da022..3d8f9f9 100644
+--- a/drivers/thermal/thermal_core.c
++++ b/drivers/thermal/thermal_core.c
+@@ -413,13 +413,16 @@ static void handle_thermal_trip(struct thermal_zone_device *tz, int trip)
+ */
+ int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp)
+ {
+- int ret = -EINVAL;
++ int ret;
+ int count;
+ int crit_temp = INT_MAX;
+ enum thermal_trip_type type;
+
+- if (!tz || IS_ERR(tz) || !tz->ops->get_temp)
+- goto exit;
++ if (!tz || IS_ERR(tz))
++ return -EINVAL;
++
++ if (!tz->ops->get_temp)
++ return -ENOSYS;
+
+ mutex_lock(&tz->lock);
+
+@@ -445,7 +448,7 @@ int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp)
+ }
+
+ mutex_unlock(&tz->lock);
+-exit:
++
+ return ret;
+ }
+ EXPORT_SYMBOL_GPL(thermal_zone_get_temp);
+@@ -454,10 +457,11 @@ void thermal_zone_device_update(struct thermal_zone_device *tz)
+ {
+ int temp, ret, count;
+
+- if (!tz->ops->get_temp)
++ ret = thermal_zone_get_temp(tz, &temp);
++
++ if (ret == -ENOSYS)
+ return;
+
+- ret = thermal_zone_get_temp(tz, &temp);
+ if (ret) {
+ if (ret != -EAGAIN)
+ dev_warn(&tz->device,
+@@ -783,10 +787,16 @@ emul_temp_store(struct device *dev, struct device_attribute *attr,
+ if (kstrtoul(buf, 10, &temperature))
+ return -EINVAL;
+
+- if (!tz->ops->set_emul_temp) {
++ if (tz->ops->set_emul_temp)
++ ret = tz->ops->set_emul_temp(tz, temperature);
++ else
++ ret = -ENOSYS;
++
++ if (ret == -ENOSYS) {
+ mutex_lock(&tz->lock);
+ tz->emul_temperature = temperature;
+ mutex_unlock(&tz->lock);
++ ret = 0;
+ } else {
+ ret = tz->ops->set_emul_temp(tz, temperature);
+ }
+--
+1.7.10.4
+
--- /dev/null
+From 8c9c4ed500e92c10dc4965dcd00692b3102a328a Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer@pengutronix.de>
+Date: Wed, 13 May 2015 10:52:37 +0200
+Subject: [PATCH 18/76] thermal: of: always set sensor related callbacks
+
+Now that the thermal core treats -ENOSYS like the callbacks were
+not present at all we no longer have to overwrite the ops during
+runtime but instead can always set them and return -ENOSYS if no
+sensor is registered.
+
+Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
+---
+ drivers/thermal/of-thermal.c | 33 +++++++++++++--------------------
+ 1 file changed, 13 insertions(+), 20 deletions(-)
+
+diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
+index c84404d..b9c35bd 100644
+--- a/drivers/thermal/of-thermal.c
++++ b/drivers/thermal/of-thermal.c
+@@ -91,7 +91,7 @@ static int of_thermal_get_temp(struct thermal_zone_device *tz,
+ {
+ struct __thermal_zone *data = tz->devdata;
+
+- if (!data->ops->get_temp)
++ if (!data->ops)
+ return -EINVAL;
+
+ return data->ops->get_temp(data->sensor_data, temp);
+@@ -178,7 +178,7 @@ static int of_thermal_set_emul_temp(struct thermal_zone_device *tz,
+ struct __thermal_zone *data = tz->devdata;
+
+ if (!data->ops || !data->ops->set_emul_temp)
+- return -EINVAL;
++ return -ENOSYS;
+
+ return data->ops->set_emul_temp(data->sensor_data, temp);
+ }
+@@ -189,8 +189,8 @@ static int of_thermal_get_trend(struct thermal_zone_device *tz, int trip,
+ struct __thermal_zone *data = tz->devdata;
+ int r;
+
+- if (!data->ops->get_trend)
+- return -EINVAL;
++ if (!data->ops || !data->ops->get_trend)
++ return -ENOSYS;
+
+ r = data->ops->get_trend(data->sensor_data, trip, trend);
+ if (r)
+@@ -366,6 +366,10 @@ static int of_thermal_get_crit_temp(struct thermal_zone_device *tz,
+ }
+
+ static struct thermal_zone_device_ops of_thermal_ops = {
++ .get_temp = of_thermal_get_temp,
++ .get_trend = of_thermal_get_trend,
++ .set_emul_temp = of_thermal_set_emul_temp,
++
+ .get_mode = of_thermal_get_mode,
+ .set_mode = of_thermal_set_mode,
+
+@@ -399,13 +403,13 @@ thermal_zone_of_add_sensor(struct device_node *zone,
+ if (!ops)
+ return ERR_PTR(-EINVAL);
+
++ if (!ops->get_temp)
++ return ERR_PTR(-EINVAL);
++
+ mutex_lock(&tzd->lock);
+ tz->ops = ops;
+ tz->sensor_data = data;
+
+- tzd->ops->get_temp = of_thermal_get_temp;
+- tzd->ops->get_trend = of_thermal_get_trend;
+- tzd->ops->set_emul_temp = of_thermal_set_emul_temp;
+ mutex_unlock(&tzd->lock);
+
+ return tzd;
+@@ -535,9 +539,6 @@ void thermal_zone_of_sensor_unregister(struct device *dev,
+ return;
+
+ mutex_lock(&tzd->lock);
+- tzd->ops->get_temp = NULL;
+- tzd->ops->get_trend = NULL;
+- tzd->ops->set_emul_temp = NULL;
+
+ tz->ops = NULL;
+ tz->sensor_data = NULL;
+@@ -845,7 +846,6 @@ int __init of_parse_thermal_zones(void)
+ {
+ struct device_node *np, *child;
+ struct __thermal_zone *tz;
+- struct thermal_zone_device_ops *ops;
+
+ np = of_find_node_by_name(NULL, "thermal-zones");
+ if (!np) {
+@@ -869,29 +869,22 @@ int __init of_parse_thermal_zones(void)
+ continue;
+ }
+
+- ops = kmemdup(&of_thermal_ops, sizeof(*ops), GFP_KERNEL);
+- if (!ops)
+- goto exit_free;
+-
+ tzp = kzalloc(sizeof(*tzp), GFP_KERNEL);
+- if (!tzp) {
+- kfree(ops);
++ if (!tzp)
+ goto exit_free;
+- }
+
+ /* No hwmon because there might be hwmon drivers registering */
+ tzp->no_hwmon = true;
+
+ zone = thermal_zone_device_register(child->name, tz->ntrips,
+ 0, tz,
+- ops, tzp,
++ &of_thermal_ops, tzp,
+ tz->passive_delay,
+ tz->polling_delay);
+ if (IS_ERR(zone)) {
+ pr_err("Failed to build %s zone %ld\n", child->name,
+ PTR_ERR(zone));
+ kfree(tzp);
+- kfree(ops);
+ of_thermal_free_zone(tz);
+ /* attempting to build remaining zones still */
+ }
+--
+1.7.10.4
+
--- /dev/null
+From 7cbee588bc6eee59c025f89cf9324943fda98934 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer@pengutronix.de>
+Date: Wed, 13 May 2015 10:52:38 +0200
+Subject: [PATCH 19/76] thermal: Make struct thermal_zone_device_ops const
+
+Now that the of thermal support no longer changes the
+thermal_zone_device_ops it can be const again.
+
+Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
+---
+ Documentation/thermal/sysfs-api.txt | 2 +-
+ drivers/acpi/thermal.c | 2 +-
+ drivers/platform/x86/acerhdf.c | 2 +-
+ drivers/platform/x86/intel_mid_thermal.c | 2 +-
+ drivers/power/power_supply_core.c | 2 +-
+ drivers/thermal/armada_thermal.c | 2 +-
+ drivers/thermal/db8500_thermal.c | 2 +-
+ drivers/thermal/dove_thermal.c | 2 +-
+ drivers/thermal/imx_thermal.c | 2 +-
+ drivers/thermal/int340x_thermal/int3400_thermal.c | 2 +-
+ drivers/thermal/int340x_thermal/int340x_thermal_zone.c | 2 +-
+ drivers/thermal/intel_soc_dts_thermal.c | 2 +-
+ drivers/thermal/kirkwood_thermal.c | 2 +-
+ drivers/thermal/of-thermal.c | 2 +-
+ drivers/thermal/rcar_thermal.c | 2 +-
+ drivers/thermal/spear_thermal.c | 2 +-
+ drivers/thermal/st/st_thermal.c | 2 +-
+ drivers/thermal/thermal_core.c | 2 +-
+ drivers/thermal/ti-soc-thermal/ti-thermal-common.c | 2 +-
+ drivers/thermal/x86_pkg_temp_thermal.c | 2 +-
+ include/linux/thermal.h | 6 +++---
+ 21 files changed, 23 insertions(+), 23 deletions(-)
+
+diff --git a/Documentation/thermal/sysfs-api.txt b/Documentation/thermal/sysfs-api.txt
+index 87519cb..bb346a2 100644
+--- a/Documentation/thermal/sysfs-api.txt
++++ b/Documentation/thermal/sysfs-api.txt
+@@ -33,7 +33,7 @@ temperature) and throttle appropriate devices.
+ 1.1 thermal zone device interface
+ 1.1.1 struct thermal_zone_device *thermal_zone_device_register(char *type,
+ int trips, int mask, void *devdata,
+- struct thermal_zone_device_ops *ops,
++ const struct thermal_zone_device_ops *ops,
+ const struct thermal_zone_params *tzp,
+ int passive_delay, int polling_delay))
+
+diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
+index 68bff60..6b11462 100644
+--- a/drivers/acpi/thermal.c
++++ b/drivers/acpi/thermal.c
+@@ -869,7 +869,7 @@ acpi_thermal_unbind_cooling_device(struct thermal_zone_device *thermal,
+ return acpi_thermal_cooling_device_cb(thermal, cdev, false);
+ }
+
+-static struct thermal_zone_device_ops acpi_thermal_zone_ops = {
++static const struct thermal_zone_device_ops acpi_thermal_zone_ops = {
+ .bind = acpi_thermal_bind_cooling_device,
+ .unbind = acpi_thermal_unbind_cooling_device,
+ .get_temp = thermal_get_temp,
+diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c
+index f2ce63c..bae9ca0 100644
+--- a/drivers/platform/x86/acerhdf.c
++++ b/drivers/platform/x86/acerhdf.c
+@@ -482,7 +482,7 @@ static int acerhdf_get_crit_temp(struct thermal_zone_device *thermal,
+ }
+
+ /* bind callback functions to thermalzone */
+-static struct thermal_zone_device_ops acerhdf_dev_ops = {
++static const struct thermal_zone_device_ops acerhdf_dev_ops = {
+ .bind = acerhdf_bind,
+ .unbind = acerhdf_unbind,
+ .get_temp = acerhdf_get_ec_temp,
+diff --git a/drivers/platform/x86/intel_mid_thermal.c b/drivers/platform/x86/intel_mid_thermal.c
+index 0944e83..069d36b 100644
+--- a/drivers/platform/x86/intel_mid_thermal.c
++++ b/drivers/platform/x86/intel_mid_thermal.c
+@@ -460,7 +460,7 @@ static int read_curr_temp(struct thermal_zone_device *tzd, unsigned long *temp)
+ }
+
+ /* Can't be const */
+-static struct thermal_zone_device_ops tzd_ops = {
++static const struct thermal_zone_device_ops tzd_ops = {
+ .get_temp = read_curr_temp,
+ };
+
+diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c
+index 87e2fd1..878cb4e 100644
+--- a/drivers/power/power_supply_core.c
++++ b/drivers/power/power_supply_core.c
+@@ -509,7 +509,7 @@ static int power_supply_read_temp(struct thermal_zone_device *tzd,
+ return ret;
+ }
+
+-static struct thermal_zone_device_ops psy_tzd_ops = {
++static const struct thermal_zone_device_ops psy_tzd_ops = {
+ .get_temp = power_supply_read_temp,
+ };
+
+diff --git a/drivers/thermal/armada_thermal.c b/drivers/thermal/armada_thermal.c
+index 26b8d32..3f59c8b 100644
+--- a/drivers/thermal/armada_thermal.c
++++ b/drivers/thermal/armada_thermal.c
+@@ -183,7 +183,7 @@ static int armada_get_temp(struct thermal_zone_device *thermal,
+ return 0;
+ }
+
+-static struct thermal_zone_device_ops ops = {
++static const struct thermal_zone_device_ops ops = {
+ .get_temp = armada_get_temp,
+ };
+
+diff --git a/drivers/thermal/db8500_thermal.c b/drivers/thermal/db8500_thermal.c
+index b3eca71..38d6aab9 100644
+--- a/drivers/thermal/db8500_thermal.c
++++ b/drivers/thermal/db8500_thermal.c
+@@ -210,7 +210,7 @@ static int db8500_sys_get_crit_temp(struct thermal_zone_device *thermal,
+ return -EINVAL;
+ }
+
+-static struct thermal_zone_device_ops thdev_ops = {
++static const struct thermal_zone_device_ops thdev_ops = {
+ .bind = db8500_cdev_bind,
+ .unbind = db8500_cdev_unbind,
+ .get_temp = db8500_sys_get_temp,
+diff --git a/drivers/thermal/dove_thermal.c b/drivers/thermal/dove_thermal.c
+index a0bc9de..e8fd627 100644
+--- a/drivers/thermal/dove_thermal.c
++++ b/drivers/thermal/dove_thermal.c
+@@ -118,7 +118,7 @@ static int dove_get_temp(struct thermal_zone_device *thermal,
+ return 0;
+ }
+
+-static struct thermal_zone_device_ops ops = {
++static const struct thermal_zone_device_ops ops = {
+ .get_temp = dove_get_temp,
+ };
+
+diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c
+index f1424f0..8a3cfed 100644
+--- a/drivers/thermal/imx_thermal.c
++++ b/drivers/thermal/imx_thermal.c
+@@ -332,7 +332,7 @@ static int imx_unbind(struct thermal_zone_device *tz,
+ return 0;
+ }
+
+-static struct thermal_zone_device_ops imx_tz_ops = {
++static const struct thermal_zone_device_ops imx_tz_ops = {
+ .bind = imx_bind,
+ .unbind = imx_unbind,
+ .get_temp = imx_get_temp,
+diff --git a/drivers/thermal/int340x_thermal/int3400_thermal.c b/drivers/thermal/int340x_thermal/int3400_thermal.c
+index 031018e..96bdf8a 100644
+--- a/drivers/thermal/int340x_thermal/int3400_thermal.c
++++ b/drivers/thermal/int340x_thermal/int3400_thermal.c
+@@ -231,7 +231,7 @@ static int int3400_thermal_set_mode(struct thermal_zone_device *thermal,
+ return result;
+ }
+
+-static struct thermal_zone_device_ops int3400_thermal_ops = {
++static const struct thermal_zone_device_ops int3400_thermal_ops = {
+ .get_temp = int3400_thermal_get_temp,
+ };
+
+diff --git a/drivers/thermal/int340x_thermal/int340x_thermal_zone.c b/drivers/thermal/int340x_thermal/int340x_thermal_zone.c
+index b9b2666..bd9f9e8 100644
+--- a/drivers/thermal/int340x_thermal/int340x_thermal_zone.c
++++ b/drivers/thermal/int340x_thermal/int340x_thermal_zone.c
+@@ -154,7 +154,7 @@ static int int340x_thermal_get_trip_hyst(struct thermal_zone_device *zone,
+ return 0;
+ }
+
+-static struct thermal_zone_device_ops int340x_thermal_zone_ops = {
++static const struct thermal_zone_device_ops int340x_thermal_zone_ops = {
+ .get_temp = int340x_thermal_get_zone_temp,
+ .get_trip_temp = int340x_thermal_get_trip_temp,
+ .get_trip_type = int340x_thermal_get_trip_type,
+diff --git a/drivers/thermal/intel_soc_dts_thermal.c b/drivers/thermal/intel_soc_dts_thermal.c
+index fd550b9..625ba6f 100644
+--- a/drivers/thermal/intel_soc_dts_thermal.c
++++ b/drivers/thermal/intel_soc_dts_thermal.c
+@@ -270,7 +270,7 @@ static int sys_get_curr_temp(struct thermal_zone_device *tzd, int *temp)
+ return 0;
+ }
+
+-static struct thermal_zone_device_ops tzone_ops = {
++static const struct thermal_zone_device_ops tzone_ops = {
+ .get_temp = sys_get_curr_temp,
+ .get_trip_temp = sys_get_trip_temp,
+ .get_trip_type = sys_get_trip_type,
+diff --git a/drivers/thermal/kirkwood_thermal.c b/drivers/thermal/kirkwood_thermal.c
+index 11041fe..abba3e2 100644
+--- a/drivers/thermal/kirkwood_thermal.c
++++ b/drivers/thermal/kirkwood_thermal.c
+@@ -60,7 +60,7 @@ static int kirkwood_get_temp(struct thermal_zone_device *thermal,
+ return 0;
+ }
+
+-static struct thermal_zone_device_ops ops = {
++static const struct thermal_zone_device_ops ops = {
+ .get_temp = kirkwood_get_temp,
+ };
+
+diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
+index b9c35bd..bd3185e 100644
+--- a/drivers/thermal/of-thermal.c
++++ b/drivers/thermal/of-thermal.c
+@@ -365,7 +365,7 @@ static int of_thermal_get_crit_temp(struct thermal_zone_device *tz,
+ return -EINVAL;
+ }
+
+-static struct thermal_zone_device_ops of_thermal_ops = {
++static const struct thermal_zone_device_ops of_thermal_ops = {
+ .get_temp = of_thermal_get_temp,
+ .get_trend = of_thermal_get_trend,
+ .set_emul_temp = of_thermal_set_emul_temp,
+diff --git a/drivers/thermal/rcar_thermal.c b/drivers/thermal/rcar_thermal.c
+index 5d4ae7d..320ceac 100644
+--- a/drivers/thermal/rcar_thermal.c
++++ b/drivers/thermal/rcar_thermal.c
+@@ -270,7 +270,7 @@ static int rcar_thermal_notify(struct thermal_zone_device *zone,
+ return 0;
+ }
+
+-static struct thermal_zone_device_ops rcar_thermal_zone_ops = {
++static const struct thermal_zone_device_ops rcar_thermal_zone_ops = {
+ .get_temp = rcar_thermal_get_temp,
+ .get_trip_type = rcar_thermal_get_trip_type,
+ .get_trip_temp = rcar_thermal_get_trip_temp,
+diff --git a/drivers/thermal/spear_thermal.c b/drivers/thermal/spear_thermal.c
+index 534dd91..ec07743 100644
+--- a/drivers/thermal/spear_thermal.c
++++ b/drivers/thermal/spear_thermal.c
+@@ -50,7 +50,7 @@ static inline int thermal_get_temp(struct thermal_zone_device *thermal,
+ return 0;
+ }
+
+-static struct thermal_zone_device_ops ops = {
++static const struct thermal_zone_device_ops ops = {
+ .get_temp = thermal_get_temp,
+ };
+
+diff --git a/drivers/thermal/st/st_thermal.c b/drivers/thermal/st/st_thermal.c
+index 44cbba9..0cb5c19 100644
+--- a/drivers/thermal/st/st_thermal.c
++++ b/drivers/thermal/st/st_thermal.c
+@@ -175,7 +175,7 @@ static int st_thermal_get_trip_temp(struct thermal_zone_device *th,
+ return 0;
+ }
+
+-static struct thermal_zone_device_ops st_tz_ops = {
++static const struct thermal_zone_device_ops st_tz_ops = {
+ .get_temp = st_thermal_get_temp,
+ .get_trip_type = st_thermal_get_trip_type,
+ .get_trip_temp = st_thermal_get_trip_temp,
+diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
+index 3d8f9f9..6bbf61f 100644
+--- a/drivers/thermal/thermal_core.c
++++ b/drivers/thermal/thermal_core.c
+@@ -1451,7 +1451,7 @@ static void remove_trip_attrs(struct thermal_zone_device *tz)
+ */
+ struct thermal_zone_device *thermal_zone_device_register(const char *type,
+ int trips, int mask, void *devdata,
+- struct thermal_zone_device_ops *ops,
++ const struct thermal_zone_device_ops *ops,
+ const struct thermal_zone_params *tzp,
+ int passive_delay, int polling_delay)
+ {
+diff --git a/drivers/thermal/ti-soc-thermal/ti-thermal-common.c b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
+index ade78eb..e9c82fc 100644
+--- a/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
++++ b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
+@@ -281,7 +281,7 @@ static const struct thermal_zone_of_device_ops ti_of_thermal_ops = {
+ .get_trend = __ti_thermal_get_trend,
+ };
+
+-static struct thermal_zone_device_ops ti_thermal_ops = {
++static const struct thermal_zone_device_ops ti_thermal_ops = {
+ .get_temp = ti_thermal_get_temp,
+ .get_trend = ti_thermal_get_trend,
+ .bind = ti_thermal_bind,
+diff --git a/drivers/thermal/x86_pkg_temp_thermal.c b/drivers/thermal/x86_pkg_temp_thermal.c
+index 054c6d45..bb2b975 100644
+--- a/drivers/thermal/x86_pkg_temp_thermal.c
++++ b/drivers/thermal/x86_pkg_temp_thermal.c
+@@ -274,7 +274,7 @@ static int sys_get_trip_type(struct thermal_zone_device *thermal,
+ }
+
+ /* Thermal zone callback registry */
+-static struct thermal_zone_device_ops tzone_ops = {
++static const struct thermal_zone_device_ops tzone_ops = {
+ .get_temp = sys_get_curr_temp,
+ .get_trip_temp = sys_get_trip_temp,
+ .get_trip_type = sys_get_trip_type,
+diff --git a/include/linux/thermal.h b/include/linux/thermal.h
+index 5c6a589..07bd5e8 100644
+--- a/include/linux/thermal.h
++++ b/include/linux/thermal.h
+@@ -181,7 +181,7 @@ struct thermal_zone_device {
+ int emul_temperature;
+ int passive;
+ unsigned int forced_passive;
+- struct thermal_zone_device_ops *ops;
++ const struct thermal_zone_device_ops *ops;
+ const struct thermal_zone_params *tzp;
+ struct thermal_governor *governor;
+ struct list_head thermal_instances;
+@@ -313,7 +313,7 @@ void thermal_zone_of_sensor_unregister(struct device *dev,
+
+ #if IS_ENABLED(CONFIG_THERMAL)
+ struct thermal_zone_device *thermal_zone_device_register(const char *, int, int,
+- void *, struct thermal_zone_device_ops *,
++ void *, const struct thermal_zone_device_ops *,
+ const struct thermal_zone_params *, int, int);
+ void thermal_zone_device_unregister(struct thermal_zone_device *);
+
+@@ -341,7 +341,7 @@ void thermal_notify_framework(struct thermal_zone_device *, int);
+ #else
+ static inline struct thermal_zone_device *thermal_zone_device_register(
+ const char *type, int trips, int mask, void *devdata,
+- struct thermal_zone_device_ops *ops,
++ const struct thermal_zone_device_ops *ops,
+ const struct thermal_zone_params *tzp,
+ int passive_delay, int polling_delay)
+ { return ERR_PTR(-ENODEV); }
+--
+1.7.10.4
+
--- /dev/null
+From 346632bc00fe71c269709702fecb474bb22e933e Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer@pengutronix.de>
+Date: Wed, 13 May 2015 10:52:39 +0200
+Subject: [PATCH 20/76] thermal: thermal: Add support for hardware-tracked
+ trip points
+
+This adds support for hardware-tracked trip points to the device tree
+thermal sensor framework.
+
+The framework supports an arbitrary number of trip points. Whenever
+the current temperature is updated, the trip points immediately
+below and above the current temperature are found. A .set_trips
+callback is then called with the temperatures. If there is no trip
+point above or below the current temperature, the passed trip
+temperature will be -INT_MAX or INT_MAX respectively. In this callback,
+the driver should program the hardware such that it is notified
+when either of these trip points are triggered. When a trip point
+is triggered, the driver should call `thermal_zone_device_update'
+for the respective thermal zone. This will cause the trip points
+to be updated again.
+
+If .set_trips is not implemented, the framework behaves as before.
+
+This patch is based on an earlier version from Mikko Perttunen
+<mikko.perttunen@kapsi.fi>
+
+Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
+---
+ drivers/thermal/thermal_core.c | 43 ++++++++++++++++++++++++++++++++++++++++
+ include/linux/thermal.h | 3 +++
+ 2 files changed, 46 insertions(+)
+
+diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
+index 6bbf61f..3ae1795 100644
+--- a/drivers/thermal/thermal_core.c
++++ b/drivers/thermal/thermal_core.c
+@@ -453,6 +453,45 @@ int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp)
+ }
+ EXPORT_SYMBOL_GPL(thermal_zone_get_temp);
+
++static void thermal_zone_set_trips(struct thermal_zone_device *tz)
++{
++ int low = -INT_MAX;
++ int high = INT_MAX;
++ int trip_temp, hysteresis;
++ int temp = tz->temperature;
++ int i;
++
++ if (!tz->ops->set_trips)
++ return;
++
++ /* No need to change trip points */
++ if (temp > tz->prev_low_trip && temp < tz->prev_high_trip)
++ return;
++
++ for (i = 0; i < tz->trips; i++) {
++ int trip_low;
++
++ tz->ops->get_trip_temp(tz, i, &trip_temp);
++ tz->ops->get_trip_hyst(tz, i, &hysteresis);
++
++ trip_low = trip_temp - hysteresis;
++
++ if (trip_low < temp && trip_low > low)
++ low = trip_low;
++
++ if (trip_temp > temp && trip_temp < high)
++ high = trip_temp;
++ }
++
++ tz->prev_low_trip = low;
++ tz->prev_high_trip = high;
++
++ dev_dbg(&tz->device, "new temperature boundaries: %d < x < %d\n",
++ low, high);
++
++ tz->ops->set_trips(tz, low, high);
++}
++
+ void thermal_zone_device_update(struct thermal_zone_device *tz)
+ {
+ int temp, ret, count;
+@@ -479,6 +518,8 @@ void thermal_zone_device_update(struct thermal_zone_device *tz)
+ dev_dbg(&tz->device, "last_temperature=%d, current_temperature=%d\n",
+ tz->last_temperature, tz->temperature);
+
++ thermal_zone_set_trips(tz);
++
+ for (count = 0; count < tz->trips; count++)
+ handle_thermal_trip(tz, count);
+ }
+@@ -1494,6 +1535,8 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type,
+ tz->trips = trips;
+ tz->passive_delay = passive_delay;
+ tz->polling_delay = polling_delay;
++ tz->prev_low_trip = INT_MAX;
++ tz->prev_high_trip = -INT_MAX;
+
+ dev_set_name(&tz->device, "thermal_zone%d", tz->id);
+ result = device_register(&tz->device);
+diff --git a/include/linux/thermal.h b/include/linux/thermal.h
+index 07bd5e8..aef6e13 100644
+--- a/include/linux/thermal.h
++++ b/include/linux/thermal.h
+@@ -87,6 +87,7 @@ struct thermal_zone_device_ops {
+ int (*unbind) (struct thermal_zone_device *,
+ struct thermal_cooling_device *);
+ int (*get_temp) (struct thermal_zone_device *, int *);
++ int (*set_trips) (struct thermal_zone_device *, int, int);
+ int (*get_mode) (struct thermal_zone_device *,
+ enum thermal_device_mode *);
+ int (*set_mode) (struct thermal_zone_device *,
+@@ -180,6 +181,8 @@ struct thermal_zone_device {
+ int last_temperature;
+ int emul_temperature;
+ int passive;
++ int prev_low_trip;
++ int prev_high_trip;
+ unsigned int forced_passive;
+ const struct thermal_zone_device_ops *ops;
+ const struct thermal_zone_params *tzp;
+--
+1.7.10.4
+
--- /dev/null
+From 525f68bb9d9f6334dbcd2b5ec99f9d797ff53618 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer@pengutronix.de>
+Date: Wed, 13 May 2015 10:52:40 +0200
+Subject: [PATCH 21/76] thermal: of: implement .set_trips for device tree
+ thermal zones
+
+Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
+---
+ drivers/thermal/of-thermal.c | 12 ++++++++++++
+ include/linux/thermal.h | 3 +++
+ 2 files changed, 15 insertions(+)
+
+diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
+index bd3185e..f8dd847 100644
+--- a/drivers/thermal/of-thermal.c
++++ b/drivers/thermal/of-thermal.c
+@@ -97,6 +97,17 @@ static int of_thermal_get_temp(struct thermal_zone_device *tz,
+ return data->ops->get_temp(data->sensor_data, temp);
+ }
+
++static int of_thermal_set_trips(struct thermal_zone_device *tz,
++ int low, int high)
++{
++ struct __thermal_zone *data = tz->devdata;
++
++ if (!data->ops || !data->ops->set_trips)
++ return -ENOSYS;
++
++ return data->ops->set_trips(data->sensor_data, low, high);
++}
++
+ /**
+ * of_thermal_get_ntrips - function to export number of available trip
+ * points.
+@@ -367,6 +378,7 @@ static int of_thermal_get_crit_temp(struct thermal_zone_device *tz,
+
+ static const struct thermal_zone_device_ops of_thermal_ops = {
+ .get_temp = of_thermal_get_temp,
++ .set_trips = of_thermal_set_trips,
+ .get_trend = of_thermal_get_trend,
+ .set_emul_temp = of_thermal_set_emul_temp,
+
+diff --git a/include/linux/thermal.h b/include/linux/thermal.h
+index aef6e13..b751f6b 100644
+--- a/include/linux/thermal.h
++++ b/include/linux/thermal.h
+@@ -267,12 +267,15 @@ struct thermal_genl_event {
+ *
+ * Optional:
+ * @get_trend: a pointer to a function that reads the sensor temperature trend.
++ * @set_trips: a pointer to a function that sets a temperature window which shall
++ * trigger an interrupt when it is left.
+ * @set_emul_temp: a pointer to a function that sets sensor emulated
+ * temperature.
+ */
+ struct thermal_zone_of_device_ops {
+ int (*get_temp)(void *, int *);
+ int (*get_trend)(void *, int, enum thermal_trend *);
++ int (*set_trips)(void *, int, int);
+ int (*set_emul_temp)(void *, int);
+ };
+
+--
+1.7.10.4
+
--- /dev/null
+From 9b799b8a4ecbf560f8fb996e8e5147a8f7b9a1b3 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer@pengutronix.de>
+Date: Wed, 13 May 2015 10:52:41 +0200
+Subject: [PATCH 22/76] dt-bindings: thermal: Add binding document for
+ Mediatek thermal controller
+
+Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
+---
+ .../bindings/thermal/mediatek-thermal.txt | 36 ++++++++++++++++++++
+ 1 file changed, 36 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/thermal/mediatek-thermal.txt
+
+diff --git a/Documentation/devicetree/bindings/thermal/mediatek-thermal.txt b/Documentation/devicetree/bindings/thermal/mediatek-thermal.txt
+new file mode 100644
+index 0000000..adf5d2c
+--- /dev/null
++++ b/Documentation/devicetree/bindings/thermal/mediatek-thermal.txt
+@@ -0,0 +1,36 @@
++* Mediatek Thermal
++
++This describes the device tree binding for the Mediatek thermal controller
++which measures the on-SoC temperatures. This device does not have its own ADC,
++instead it directly controls the AUXADC via AHB bus accesses. For this reason
++this device needs phandles to the AUXADC.
++
++Required properties:
++- compatible: "mediatek,mt8173-thermal"
++- reg: Address range of the thermal controller
++- interrupts: IRQ for the thermal controller
++- clocks, clock-names: Clocks needed for the thermal controller. required
++ clocks are:
++ "therm": Main clock needed for register access
++ "auxadc": The AUXADC clock
++- resets, reset-names: Reference to the reset controller controlling the thermal
++ controller. Required reset-names:
++ "therm": The main reset line
++- auxadc: A phandle to the AUXADC which the thermal controller uses
++- apmixedsys: A phandle to the APMIXEDSYS controller.
++- #thermal-sensor-cells : Should be 1. See ./thermal.txt for a description
++
++Example:
++
++ thermal: thermal@1100b000 {
++ #thermal-sensor-cells = <1>;
++ compatible = "mediatek,mt8173-thermal";
++ reg = <0 0x1100b000 0 0x1000>;
++ interrupts = <0 70 IRQ_TYPE_LEVEL_LOW>;
++ clocks = <&pericfg CLK_PERI_THERM>, <&pericfg CLK_PERI_AUXADC>;
++ clock-names = "therm", "auxadc";
++ resets = <&pericfg MT8173_PERI_THERM_SW_RST>;
++ reset-names = "therm";
++ auxadc = <&auxadc>;
++ apmixedsys = <&apmixedsys>;
++ };
+--
+1.7.10.4
+
--- /dev/null
+From 014330a304100782a26bc7df02778c8c386b2857 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer@pengutronix.de>
+Date: Wed, 13 May 2015 10:52:42 +0200
+Subject: [PATCH 23/76] thermal: Add Mediatek thermal controller support
+
+This adds support for the Mediatek thermal controller found on MT8173
+and likely other SoCs.
+The controller is a bit special. It does not have its own ADC, instead
+it controls the on-SoC AUXADC via AHB bus accesses. For this reason
+we need the physical address of the AUXADC. Also it controls a mux
+using AHB bus accesses, so we need the APMIXEDSYS physical address aswell.
+
+Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
+---
+ drivers/thermal/Kconfig | 8 +
+ drivers/thermal/Makefile | 1 +
+ drivers/thermal/mtk_thermal.c | 728 +++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 737 insertions(+)
+ create mode 100644 drivers/thermal/mtk_thermal.c
+
+diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
+index af40db0..3aa5500 100644
+--- a/drivers/thermal/Kconfig
++++ b/drivers/thermal/Kconfig
+@@ -285,6 +285,14 @@ config ACPI_THERMAL_REL
+ tristate
+ depends on ACPI
+
++config MTK_THERMAL
++ tristate "Temperature sensor driver for mediatek SoCs"
++ depends on ARCH_MEDIATEK || COMPILE_TEST
++ default y
++ help
++ Enable this option if you want to have support for thermal management
++ controller present in Mediatek SoCs
++
+ menu "Texas Instruments thermal drivers"
+ source "drivers/thermal/ti-soc-thermal/Kconfig"
+ endmenu
+diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
+index fa0dc48..51cfab7 100644
+--- a/drivers/thermal/Makefile
++++ b/drivers/thermal/Makefile
+@@ -39,3 +39,4 @@ obj-$(CONFIG_TI_SOC_THERMAL) += ti-soc-thermal/
+ obj-$(CONFIG_INT340X_THERMAL) += int340x_thermal/
+ obj-$(CONFIG_ST_THERMAL) += st/
+ obj-$(CONFIG_TEGRA_SOCTHERM) += tegra_soctherm.o
++obj-$(CONFIG_MTK_THERMAL) += mtk_thermal.o
+diff --git a/drivers/thermal/mtk_thermal.c b/drivers/thermal/mtk_thermal.c
+new file mode 100644
+index 0000000..27aab12
+--- /dev/null
++++ b/drivers/thermal/mtk_thermal.c
+@@ -0,0 +1,728 @@
++/*
++ * Copyright (c) 2014 MediaTek Inc.
++ * Author: Hanyi.Wu <hanyi.wu@mediatek.com>
++ *
++ * 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.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/dmi.h>
++#include <linux/thermal.h>
++#include <linux/platform_device.h>
++#include <linux/types.h>
++#include <linux/delay.h>
++#include <linux/slab.h>
++#include <linux/clk.h>
++#include <linux/time.h>
++#include <linux/of.h>
++#include <linux/of_irq.h>
++#include <linux/of_address.h>
++#include <linux/interrupt.h>
++#include <linux/reset.h>
++
++/* AUXADC Registers */
++#define AUXADC_CON0_V 0x000
++#define AUXADC_CON1_V 0x004
++#define AUXADC_CON1_SET_V 0x008
++#define AUXADC_CON1_CLR_V 0x00c
++#define AUXADC_CON2_V 0x010
++#define AUXADC_DATA(channel) (0x14 + (channel) * 4)
++#define AUXADC_MISC_V 0x094
++
++#define AUXADC_CON1_CHANNEL(x) (1 << (x))
++
++/* Thermal Controller Registers */
++#define TEMPMONCTL0 0x000
++#define TEMPMONCTL1 0x004
++#define TEMPMONCTL2 0x008
++#define TEMPMONINT 0x00c
++#define TEMPMONINTSTS 0x010
++#define TEMPMONIDET0 0x014
++#define TEMPMONIDET1 0x018
++#define TEMPMONIDET2 0x01c
++#define TEMPH2NTHRE 0x024
++#define TEMPHTHRE 0x028
++#define TEMPCTHRE 0x02c
++#define TEMPOFFSETH 0x030
++#define TEMPOFFSETL 0x034
++#define TEMPMSRCTL0 0x038
++#define TEMPMSRCTL1 0x03c
++#define TEMPAHBPOLL 0x040
++#define TEMPAHBTO 0x044
++#define TEMPADCPNP0 0x048
++#define TEMPADCPNP1 0x04c
++#define TEMPADCPNP2 0x050
++#define TEMPADCPNP3 0x0b4
++
++#define TEMPADCMUX 0x054
++#define TEMPADCEXT 0x058
++#define TEMPADCEXT1 0x05c
++#define TEMPADCEN 0x060
++#define TEMPPNPMUXADDR 0x064
++#define TEMPADCMUXADDR 0x068
++#define TEMPADCEXTADDR 0x06c
++#define TEMPADCEXT1ADDR 0x070
++#define TEMPADCENADDR 0x074
++#define TEMPADCVALIDADDR 0x078
++#define TEMPADCVOLTADDR 0x07c
++#define TEMPRDCTRL 0x080
++#define TEMPADCVALIDMASK 0x084
++#define TEMPADCVOLTAGESHIFT 0x088
++#define TEMPADCWRITECTRL 0x08c
++#define TEMPMSR0 0x090
++#define TEMPMSR1 0x094
++#define TEMPMSR2 0x098
++#define TEMPMSR3 0x0B8
++
++#define TEMPIMMD0 0x0a0
++#define TEMPIMMD1 0x0a4
++#define TEMPIMMD2 0x0a8
++
++#define TEMPPROTCTL 0x0c0
++#define TEMPPROTTA 0x0c4
++#define TEMPPROTTB 0x0c8
++#define TEMPPROTTC 0x0cc
++
++#define TEMPSPARE0 0x0f0
++#define TEMPSPARE1 0x0f4
++#define TEMPSPARE2 0x0f8
++#define TEMPSPARE3 0x0fc
++
++#define PTPCORESEL 0x400
++#define THERMINTST 0x404
++#define PTPODINTST 0x408
++#define THSTAGE0ST 0x40c
++#define THSTAGE1ST 0x410
++#define THSTAGE2ST 0x414
++#define THAHBST0 0x418
++#define THAHBST1 0x41c /* Only for DE debug */
++#define PTPSPARE0 0x420
++#define PTPSPARE1 0x424
++#define PTPSPARE2 0x428
++#define PTPSPARE3 0x42c
++#define THSLPEVEB 0x430
++
++#define TEMPMONINT_COLD(sp) ((1 << 0) << ((sp) * 5))
++#define TEMPMONINT_HOT(sp) ((1 << 1) << ((sp) * 5))
++#define TEMPMONINT_LOW_OFS(sp) ((1 << 2) << ((sp) * 5))
++#define TEMPMONINT_HIGH_OFS(sp) ((1 << 3) << ((sp) * 5))
++#define TEMPMONINT_HOT_TO_NORM(sp) ((1 << 4) << ((sp) * 5))
++#define TEMPMONINT_TIMEOUT (1 << 15)
++#define TEMPMONINT_IMMEDIATE_SENSE(sp) (1 << (16 + (sp)))
++#define TEMPMONINT_FILTER_SENSE(sp) (1 << (19 + (sp)))
++
++#define TEMPADCWRITECTRL_ADC_PNP_WRITE (1 << 0)
++#define TEMPADCWRITECTRL_ADC_MUX_WRITE (1 << 1)
++#define TEMPADCWRITECTRL_ADC_EXTRA_WRITE (1 << 2)
++#define TEMPADCWRITECTRL_ADC_EXTRA1_WRITE (1 << 3)
++
++#define TEMPADCVALIDMASK_VALID_HIGH (1 << 5)
++#define TEMPADCVALIDMASK_VALID_POS(bit) (bit)
++
++#define TEMPPROTCTL_AVERAGE (0 << 16)
++#define TEMPPROTCTL_MAXIMUM (1 << 16)
++#define TEMPPROTCTL_SELECTED (2 << 16)
++
++#define MT8173_THERMAL_ZONE_CA57 0
++#define MT8173_THERMAL_ZONE_CA53 1
++#define MT8173_THERMAL_ZONE_GPU 2
++#define MT8173_THERMAL_ZONE_CORE 3
++
++#define MT8173_TS1 0
++#define MT8173_TS2 1
++#define MT8173_TS3 2
++#define MT8173_TS4 3
++#define MT8173_TSABB 4
++
++/* AUXADC channel 11 is used for the temperature sensors */
++#define MT8173_TEMP_AUXADC_CHANNEL 11
++
++/* The total number of temperature sensors in the MT8173 */
++#define MT8173_NUM_SENSORS 5
++
++/* The number of banks in the MT8173 */
++#define MT8173_NUM_BANKS 4
++
++/* The number of sensing points per bank */
++#define MT8173_NUM_SENSING_POINTS 4
++
++#define THERMAL_NAME "mtk-thermal"
++
++struct mtk_thermal;
++
++struct mtk_thermal_bank {
++ struct mtk_thermal *mt;
++ struct thermal_zone_device *tz;
++ int id;
++};
++
++struct mtk_thermal {
++ struct device *dev;
++ void __iomem *thermal_base;
++ void __iomem *auxadc_base;
++
++ u64 auxadc_phys_base;
++ u64 apmixed_phys_base;
++ struct reset_control *reset;
++ struct clk *clk_peri_therm;
++ struct clk *clk_auxadc;
++
++ struct mtk_thermal_bank banks[MT8173_NUM_BANKS];
++
++ struct mutex lock;
++
++ /* Calibration values */
++ s32 adc_ge;
++ s32 adc_oe;
++ s32 degc_cali;
++ s32 o_slope;
++ s32 vts;
++};
++
++struct mtk_thermal_bank_cfg {
++ unsigned int enable_mask;
++ unsigned int sensors[4];
++};
++
++static int sensor_mux_values[MT8173_NUM_SENSORS] = { 0, 1, 2, 3, 16 };
++
++/*
++ * The MT8173 thermal controller has four banks. Each bank can read up to
++ * four temperature sensors simultaneously. The MT8173 has a total of 5
++ * temperature sensors. We use each bank to measure a certain area of the
++ * SoC. Since TS2 is located centrally in the SoC it is influenced by multiple
++ * areas, hence is used in different banks.
++ */
++static struct mtk_thermal_bank_cfg bank_data[] = {
++ {
++ .enable_mask = 3,
++ .sensors = { MT8173_TS2, MT8173_TS3 },
++ }, {
++ .enable_mask = 3,
++ .sensors = { MT8173_TS2, MT8173_TS4 },
++ }, {
++ .enable_mask = 7,
++ .sensors = { MT8173_TS1, MT8173_TS2, MT8173_TSABB },
++ }, {
++ .enable_mask = 1,
++ .sensors = { MT8173_TS2 },
++ },
++};
++
++static int tempmsr_ofs[MT8173_NUM_SENSING_POINTS] = {
++ TEMPMSR0, TEMPMSR1, TEMPMSR2, TEMPMSR3
++};
++
++static int tempadcpnp_ofs[MT8173_NUM_SENSING_POINTS] = {
++ TEMPADCPNP0, TEMPADCPNP1, TEMPADCPNP2, TEMPADCPNP3
++};
++
++/**
++ * raw_to_mcelsius - convert a raw ADC value to mcelsius
++ * @mt: The thermal controller
++ * @raw: raw ADC value
++ *
++ * This converts the raw ADC value to mcelsius using the SoC specific
++ * calibration constants
++ */
++static int raw_to_mcelsius(struct mtk_thermal *mt, u32 raw)
++{
++ s32 format_1, format_2, format_3, format_4;
++ s32 xtoomt;
++ s32 gain;
++
++ raw &= 0xfff;
++
++ gain = (10000 + mt->adc_ge);
++
++ xtoomt = ((((mt->vts + 3350 - mt->adc_oe) * 10000) / 4096) * 10000) /
++ gain;
++
++ format_1 = ((mt->degc_cali * 10) >> 1);
++ format_2 = (raw - mt->adc_oe);
++ format_3 = (((((format_2) * 10000) >> 12) * 10000) / gain) - xtoomt;
++ format_3 = format_3 * 15 / 18;
++ format_4 = ((format_3 * 100) / (165 + mt->o_slope));
++ format_4 = format_4 - (format_4 << 1);
++
++ return (format_1 + format_4) * 100;
++}
++
++/**
++ * mcelsius_to_raw - convert mcelsius to raw ADC value
++ * @mt: The thermal controller
++ * @temp: The temperature in mcelsius
++ *
++ * This converts a temperature in mcelsius to a raw ADC value, needed to
++ * calculate the trigger values for interrupt generation.
++ */
++static u32 mcelsius_to_raw(struct mtk_thermal *mt, int temp)
++{
++ s32 format_1, format_2, format_3, format_4;
++ s32 xtoomt;
++ s32 gain;
++
++ gain = (10000 + mt->adc_ge);
++
++ xtoomt = ((((mt->vts + 3350 - mt->adc_oe) * 10000) / 4096) * 10000) /
++ gain;
++
++ format_1 = temp - (mt->degc_cali * 1000 / 2);
++ format_2 = format_1 * (165 + mt->o_slope) * 18 / 15;
++ format_2 = format_2 - 2 * format_2;
++ format_3 = format_2 / 1000 + xtoomt * 10;
++ format_4 = (format_3 * 4096 / 10000 * gain) / 100000 + mt->adc_oe;
++
++ return format_4;
++}
++
++/**
++ * mtk_thermal_get_bank - get bank
++ * @bank: The bank
++ *
++ * The bank registers are banked, we have to select a bank in the
++ * PTPCORESEL register to access it.
++ */
++static void mtk_thermal_get_bank(struct mtk_thermal_bank *bank)
++{
++ struct mtk_thermal *mt = bank->mt;
++ u32 val;
++
++ mutex_lock(&mt->lock);
++
++ val = readl(mt->thermal_base + PTPCORESEL);
++ val &= ~0xf;
++ val |= bank->id;
++ writel(val, mt->thermal_base + PTPCORESEL);
++}
++
++/**
++ * mtk_thermal_put_bank - release bank
++ * @bank: The bank
++ *
++ * release a bank previously taken with mtk_thermal_get_bank,
++ */
++static void mtk_thermal_put_bank(struct mtk_thermal_bank *bank)
++{
++ struct mtk_thermal *mt = bank->mt;
++
++ mutex_unlock(&mt->lock);
++}
++
++/**
++ * mtk_thermal_bank_temperature - get the temperature of a bank
++ * @bank: The bank
++ *
++ * The temperature of a bank is considered the maximum temperature of
++ * the sensors associated to the bank.
++ */
++static int mtk_thermal_bank_temperature(struct mtk_thermal_bank *bank)
++{
++ struct mtk_thermal *mt = bank->mt;
++ int temp, i, max;
++ u32 raw;
++
++ temp = max = -INT_MAX;
++
++ for (i = 0; i < 4; i++) {
++ int sensno;
++
++ if (!(bank_data[bank->id].enable_mask & (1 << i)))
++ continue;
++
++ raw = readl(mt->thermal_base + tempmsr_ofs[i]);
++
++ sensno = bank_data[bank->id].sensors[i];
++ temp = raw_to_mcelsius(mt, raw);
++
++ if (temp > max)
++ max = temp;
++ }
++
++ return max;
++}
++
++static void mtk_thermal_irq_bank(struct mtk_thermal_bank *bank)
++{
++ struct mtk_thermal *mt = bank->mt;
++ int sp;
++ u32 irqstat;
++ bool update = false;
++
++ mtk_thermal_get_bank(bank);
++
++ irqstat = readl(mt->thermal_base + TEMPMONINTSTS);
++
++ mtk_thermal_put_bank(bank);
++
++ for (sp = 0; sp < 3; sp++) {
++ if (irqstat & TEMPMONINT_LOW_OFS(sp)) {
++ update = true;
++ dev_vdbg(mt->dev, "bank %d sensor %d low offset interrupt\n",
++ bank->id, sp);
++ }
++
++ if (irqstat & TEMPMONINT_HIGH_OFS(sp)) {
++ update = true;
++ dev_vdbg(mt->dev, "bank %d sensor %d high offset interrupt\n",
++ bank->id, sp);
++ }
++ }
++
++ if (update)
++ thermal_zone_device_update(bank->tz);
++}
++
++static irqreturn_t mtk_thermal_irq(int irq, void *dev_id)
++{
++ struct mtk_thermal *mt = dev_id;
++ u32 irqstat = 0;
++ int i;
++
++ irqstat = readl(mt->thermal_base + THERMINTST);
++
++ dev_vdbg(mt->dev, "thermal_interrupt_handler : THERMINTST = 0x%x\n",
++ irqstat);
++
++ for (i = 0; i < MT8173_NUM_BANKS; i++) {
++ if (!(irqstat & (1 << i)))
++ mtk_thermal_irq_bank(&mt->banks[i]);
++ }
++
++ return IRQ_HANDLED;
++}
++
++static int mtk_read_temp(void *data, int *temp)
++{
++ struct mtk_thermal_bank *bank = data;
++
++ mtk_thermal_get_bank(bank);
++
++ *temp = mtk_thermal_bank_temperature(bank);
++
++ mtk_thermal_put_bank(bank);
++
++ return 0;
++}
++
++static int mtk_set_trips(void *data, int low, int high)
++{
++ struct mtk_thermal_bank *bank = data;
++ struct mtk_thermal *mt = bank->mt;
++ int i;
++ u32 val, enable_mask;
++ u32 raw_low, raw_high;
++
++ raw_low = mcelsius_to_raw(mt, low);
++ raw_high = mcelsius_to_raw(mt, high);
++
++ mtk_thermal_get_bank(bank);
++
++ writel(0x0, mt->thermal_base + TEMPMONINT);
++
++ writel(TEMPPROTCTL_SELECTED, mt->thermal_base + TEMPPROTCTL);
++
++ writel(raw_low, mt->thermal_base + TEMPOFFSETL);
++ writel(raw_high, mt->thermal_base + TEMPOFFSETH);
++
++ enable_mask = readl(mt->thermal_base + TEMPMONCTL0);
++
++ val = 0;
++ for (i = 0; i < MT8173_NUM_SENSING_POINTS; i++)
++ if (enable_mask & (1 << i))
++ val |= TEMPMONINT_LOW_OFS(i) | TEMPMONINT_HIGH_OFS(i);
++
++ writel(val, mt->thermal_base + TEMPMONINT);
++
++ mtk_thermal_put_bank(bank);
++
++ dev_dbg(mt->dev, "new boundaries: %d (0x%04x) < x < %d (0x%04x)\n",
++ low, mcelsius_to_raw(mt, low),
++ high, mcelsius_to_raw(mt, high));
++
++ return 0;
++}
++
++static const struct thermal_zone_of_device_ops mtk_thermal_ops = {
++ .get_temp = mtk_read_temp,
++ .set_trips = mtk_set_trips,
++};
++
++static void mtk_thermal_init_bank(struct mtk_thermal_bank *bank)
++{
++ struct mtk_thermal *mt = bank->mt;
++ struct mtk_thermal_bank_cfg *cfg = &bank_data[bank->id];
++ int i;
++
++ mtk_thermal_get_bank(bank);
++
++ /* bus clock 66M counting unit is 12 * 15.15ns * 256 = 46.540us */
++ writel(0x0000000c, mt->thermal_base + TEMPMONCTL1);
++
++ /*
++ * filt interval is 1 * 46.540us = 46.54us,
++ * sen interval is 429 * 46.540us = 19.96ms
++ */
++ writel(0x000101ad, mt->thermal_base + TEMPMONCTL2);
++
++ /* poll is set to 10u */
++ writel(0x00000300, mt->thermal_base + TEMPAHBPOLL);
++
++ /* temperature sampling control, 1 sample */
++ writel(0x00000000, mt->thermal_base + TEMPMSRCTL0);
++
++ /* exceed this polling time, IRQ would be inserted */
++ writel(0xffffffff, mt->thermal_base + TEMPAHBTO);
++
++ /* number of interrupts per event, 1 is enough */
++ writel(0x0, mt->thermal_base + TEMPMONIDET0);
++ writel(0x0, mt->thermal_base + TEMPMONIDET1);
++
++ /*
++ * The MT8173 thermal controller does not have its own ADC. Instead it
++ * uses AHB bus accesses to control the AUXADC. To do this the thermal
++ * controller has to be programmed with the physical addresses of the
++ * AUXADC registers and with the various bit positions in the AUXADC.
++ * Also the thermal controller controls a mux in the APMIXEDSYS register
++ * space.
++ */
++
++ /*
++ * this value will be stored to TEMPPNPMUXADDR (TEMPSPARE0)
++ * automatically by hw
++ */
++ writel(1 << MT8173_TEMP_AUXADC_CHANNEL, mt->thermal_base + TEMPADCMUX);
++
++ /* AHB address for auxadc mux selection */
++ writel(mt->auxadc_phys_base + 0x00c,
++ mt->thermal_base + TEMPADCMUXADDR);
++
++ /* AHB address for pnp sensor mux selection */
++ writel(mt->apmixed_phys_base + 0x0604,
++ mt->thermal_base + TEMPPNPMUXADDR);
++
++ /* AHB value for auxadc enable */
++ writel(1 << MT8173_TEMP_AUXADC_CHANNEL, mt->thermal_base + TEMPADCEN);
++
++ /* AHB address for auxadc enable (channel 0 immediate mode selected) */
++ writel(mt->auxadc_phys_base + AUXADC_CON1_SET_V,
++ mt->thermal_base + TEMPADCENADDR);
++
++ /* AHB address for auxadc valid bit */
++ writel(mt->auxadc_phys_base + AUXADC_DATA(MT8173_TEMP_AUXADC_CHANNEL),
++ mt->thermal_base + TEMPADCVALIDADDR);
++
++ /* AHB address for auxadc voltage output */
++ writel(mt->auxadc_phys_base + AUXADC_DATA(MT8173_TEMP_AUXADC_CHANNEL),
++ mt->thermal_base + TEMPADCVOLTADDR);
++
++ /* read valid & voltage are at the same register */
++ writel(0x0, mt->thermal_base + TEMPRDCTRL);
++
++ /* indicate where the valid bit is */
++ writel(TEMPADCVALIDMASK_VALID_HIGH | TEMPADCVALIDMASK_VALID_POS(12),
++ mt->thermal_base + TEMPADCVALIDMASK);
++
++ /* no shift */
++ writel(0x0, mt->thermal_base + TEMPADCVOLTAGESHIFT);
++
++ /* enable auxadc mux write transaction */
++ writel(TEMPADCWRITECTRL_ADC_MUX_WRITE,
++ mt->thermal_base + TEMPADCWRITECTRL);
++
++ for (i = 0; i < MT8173_NUM_SENSING_POINTS; i++)
++ writel(sensor_mux_values[cfg->sensors[i]],
++ mt->thermal_base + tempadcpnp_ofs[i]);
++
++ writel(cfg->enable_mask, mt->thermal_base + TEMPMONCTL0);
++
++ writel(TEMPADCWRITECTRL_ADC_PNP_WRITE | TEMPADCWRITECTRL_ADC_MUX_WRITE,
++ mt->thermal_base + TEMPADCWRITECTRL);
++
++ mtk_thermal_put_bank(bank);
++}
++
++static u64 of_get_phys_base(struct device_node *np)
++{
++ u64 size64;
++ const __be32 *regaddr_p;
++
++ regaddr_p = of_get_address(np, 0, &size64, NULL);
++ if (!regaddr_p)
++ return OF_BAD_ADDR;
++
++ return of_translate_address(np, regaddr_p);
++}
++
++static int mtk_thermal_probe(struct platform_device *pdev)
++{
++ int ret, i;
++ struct device_node *auxadc, *apmixedsys, *np = pdev->dev.of_node;
++ int irq;
++ struct mtk_thermal *mt;
++ struct resource *res;
++
++ mt = devm_kzalloc(&pdev->dev, sizeof(*mt), GFP_KERNEL);
++ if (!mt)
++ return -ENOMEM;
++
++ mt->clk_peri_therm = devm_clk_get(&pdev->dev, "therm");
++ if (IS_ERR(mt->clk_peri_therm))
++ return PTR_ERR(mt->clk_peri_therm);
++
++ mt->clk_auxadc = devm_clk_get(&pdev->dev, "auxadc");
++ if (IS_ERR(mt->clk_auxadc))
++ return PTR_ERR(mt->clk_auxadc);
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ mt->thermal_base = devm_ioremap_resource(&pdev->dev, res);
++ if (IS_ERR(mt->thermal_base))
++ return PTR_ERR(mt->thermal_base);
++
++ mt->reset = devm_reset_control_get(&pdev->dev, "therm");
++ if (IS_ERR(mt->reset)) {
++ ret = PTR_ERR(mt->reset);
++ dev_err(&pdev->dev, "cannot get reset: %d\n", ret);
++ return ret;
++ }
++
++ mutex_init(&mt->lock);
++
++ mt->dev = &pdev->dev;
++
++ auxadc = of_parse_phandle(np, "auxadc", 0);
++ if (!auxadc) {
++ dev_err(&pdev->dev, "missing auxadc node\n");
++ return -ENODEV;
++ }
++
++ mt->auxadc_phys_base = of_get_phys_base(auxadc);
++ if (mt->auxadc_phys_base == OF_BAD_ADDR) {
++ dev_err(&pdev->dev, "Can't get auxadc phys address\n");
++ return -EINVAL;
++ }
++
++ apmixedsys = of_parse_phandle(np, "apmixedsys", 0);
++ if (!apmixedsys) {
++ dev_err(&pdev->dev, "missing apmixedsys node\n");
++ return -ENODEV;
++ }
++
++ mt->apmixed_phys_base = of_get_phys_base(apmixedsys);
++ if (mt->apmixed_phys_base == OF_BAD_ADDR) {
++ dev_err(&pdev->dev, "Can't get auxadc phys address\n");
++ return -EINVAL;
++ }
++
++ irq = platform_get_irq(pdev, 0);
++ if (!irq) {
++ dev_err(&pdev->dev, "Can't find irq\n");
++ return -EINVAL;
++ }
++
++ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, mtk_thermal_irq,
++ IRQF_ONESHOT, THERMAL_NAME, mt);
++ if (ret) {
++ dev_err(&pdev->dev, "Can't request irq %d: %d\n", irq, ret);
++ return ret;
++ }
++
++ ret = clk_prepare_enable(mt->clk_auxadc);
++ if (ret) {
++ dev_err(&pdev->dev, "Can't enable auxadc clk: %d\n", ret);
++ return ret;
++ }
++
++ reset_control_reset(mt->reset);
++
++ ret = clk_prepare_enable(mt->clk_peri_therm);
++ if (ret) {
++ dev_err(&pdev->dev, "Can't enable peri clk: %d\n", ret);
++ goto err_enable_clk;
++ }
++
++ /*
++ * These calibration values should finally be provided by the
++ * firmware or fuses. For now use default values.
++ */
++ mt->adc_ge = ((512 - 512) * 10000) / 4096;
++ mt->adc_oe = 512 - 512;
++ mt->degc_cali = 40;
++ mt->o_slope = 0;
++ mt->vts = 260;
++
++ for (i = 0; i < MT8173_NUM_BANKS; i++) {
++ struct mtk_thermal_bank *bank = &mt->banks[i];
++
++ bank->id = i;
++ bank->mt = mt;
++ mtk_thermal_init_bank(&mt->banks[i]);
++ }
++
++ platform_set_drvdata(pdev, mt);
++
++ /*
++ * This is needed after initialising the banks because otherwise
++ * the first temperature read contains bogus high temperatures which
++ * immediately cause a system shutdown.
++ */
++ msleep(100);
++
++ for (i = 0; i < MT8173_NUM_BANKS; i++) {
++ struct mtk_thermal_bank *bank = &mt->banks[i];
++
++ bank->tz = thermal_zone_of_sensor_register(&pdev->dev, i, bank,
++ &mtk_thermal_ops);
++ }
++
++ return 0;
++
++err_enable_clk:
++ clk_disable_unprepare(mt->clk_peri_therm);
++
++ return ret;
++}
++
++static int mtk_thermal_remove(struct platform_device *pdev)
++{
++ struct mtk_thermal *mt = platform_get_drvdata(pdev);
++ int i;
++
++ for (i = 0; i < MT8173_NUM_BANKS; i++) {
++ struct mtk_thermal_bank *bank = &mt->banks[i];
++
++ if (!IS_ERR(bank))
++ thermal_zone_of_sensor_unregister(&pdev->dev, bank->tz);
++ }
++
++ clk_disable_unprepare(mt->clk_peri_therm);
++ clk_disable_unprepare(mt->clk_auxadc);
++
++ return 0;
++}
++
++static const struct of_device_id mtk_thermal_of_match[] = {
++ {
++ .compatible = "mediatek,mt8173-thermal",
++ }, {
++ },
++};
++
++static struct platform_driver mtk_thermal_driver = {
++ .probe = mtk_thermal_probe,
++ .remove = mtk_thermal_remove,
++ .driver = {
++ .name = THERMAL_NAME,
++ .of_match_table = mtk_thermal_of_match,
++ },
++};
++
++module_platform_driver(mtk_thermal_driver);
+--
+1.7.10.4
+
--- /dev/null
+From 720e25e5c821336f7fa0c5fb564475c791c00340 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer@pengutronix.de>
+Date: Wed, 13 May 2015 10:52:43 +0200
+Subject: [PATCH 24/76] ARM64: dts: mt8173: Add thermal/auxadc device nodes
+
+Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
+---
+ arch/arm64/boot/dts/mediatek/mt8173.dtsi | 18 ++++++++++++++++++
+ 1 file changed, 18 insertions(+)
+
+diff --git a/arch/arm64/boot/dts/mediatek/mt8173.dtsi b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
+index 924fdb6..50d424f 100644
+--- a/arch/arm64/boot/dts/mediatek/mt8173.dtsi
++++ b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
+@@ -147,6 +147,11 @@
+ (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
+ };
+
++ auxadc: auxadc@11001000 {
++ compatible = "mediatek,mt8173-auxadc";
++ reg = <0 0x11001000 0 0x1000>;
++ };
++
+ uart0: serial@11002000 {
+ compatible = "mediatek,mt8173-uart",
+ "mediatek,mt6577-uart";
+@@ -182,6 +187,19 @@
+ clocks = <&uart_clk>;
+ status = "disabled";
+ };
++
++ thermal: thermal@1100b000 {
++ #thermal-sensor-cells = <1>;
++ compatible = "mediatek,mt8173-thermal";
++ reg = <0 0x1100b000 0 0x1000>;
++ interrupts = <0 70 IRQ_TYPE_LEVEL_LOW>;
++ clocks = <&pericfg CLK_PERI_THERM>, <&pericfg CLK_PERI_AUXADC>;
++ clock-names = "therm", "auxadc";
++ resets = <&pericfg MT8173_PERI_THERM_SW_RST>;
++ reset-names = "therm";
++ auxadc = <&auxadc>;
++ apmixedsys = <&apmixedsys>;
++ };
+ };
+
+ };
+--
+1.7.10.4
+
--- /dev/null
+From a6de66d3cf5add25f2b8913332117f3334db506e Mon Sep 17 00:00:00 2001
+From: Leilk Liu <leilk.liu@mediatek.com>
+Date: Fri, 8 May 2015 16:55:41 +0800
+Subject: [PATCH 25/76] dt-bindings: ARM: Mediatek: Document devicetree
+ bindings for spi bus
+
+Signed-off-by: Leilk Liu <leilk.liu@mediatek.com>
+---
+ .../devicetree/bindings/spi/spi-mt65xx.txt | 32 ++++++++++++++++++++
+ 1 file changed, 32 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/spi/spi-mt65xx.txt
+
+diff --git a/Documentation/devicetree/bindings/spi/spi-mt65xx.txt b/Documentation/devicetree/bindings/spi/spi-mt65xx.txt
+new file mode 100644
+index 0000000..04c28fd
+--- /dev/null
++++ b/Documentation/devicetree/bindings/spi/spi-mt65xx.txt
+@@ -0,0 +1,32 @@
++MTK SPI device
++
++Required properties:
++- compatible: should be one of the following.
++ - mediatek,mt8173-spi: for mt8173 platforms
++ - mediatek,mt8135-spi: for mt8135 platforms
++ - mediatek,mt6589-spi: for mt6589 platforms
++
++- reg: Address and length of the register set for the device
++
++- interrupts: Should contain spi interrupt
++
++- clock-names: tuple listing input clock names.
++ Required elements: "main"
++
++- clocks: phandles to input clocks.
++
++- pad-select: should specify spi pad used, only required for MT8173.
++ This value should be 0~3.
++
++Example:
++
++- SoC Specific Portion:
++spi: spi@1100a000 {
++ compatible = "mediatek,mt8173-spi";
++ reg = <0 0x1100a000 0 0x1000>;
++ interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_LOW>;
++ clocks = <&pericfg PERI_SPI0>;
++ clock-names = "main";
++ pad-select = <1>;
++ status = "disabled";
++};
+--
+1.7.10.4
+
--- /dev/null
+From 047222cfefe97ef8706f03117bc8deada4cb4ddd Mon Sep 17 00:00:00 2001
+From: Leilk Liu <leilk.liu@mediatek.com>
+Date: Fri, 8 May 2015 16:55:42 +0800
+Subject: [PATCH 26/76] spi: mediatek: Add spi bus for Mediatek MT8173
+
+This patch adds basic spi bus for MT8173.
+
+Signed-off-by: Leilk Liu <leilk.liu@mediatek.com>
+---
+ drivers/spi/Kconfig | 10 +
+ drivers/spi/Makefile | 1 +
+ drivers/spi/spi-mt65xx.c | 622 ++++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 633 insertions(+)
+ create mode 100644 drivers/spi/spi-mt65xx.c
+
+diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
+index 72b0590..53dbea3 100644
+--- a/drivers/spi/Kconfig
++++ b/drivers/spi/Kconfig
+@@ -325,6 +325,16 @@ config SPI_MESON_SPIFC
+ This enables master mode support for the SPIFC (SPI flash
+ controller) available in Amlogic Meson SoCs.
+
++config SPI_MT65XX
++ tristate "MediaTek SPI controller"
++ depends on ARCH_MEDIATEK || COMPILE_TEST
++ select SPI_BITBANG
++ help
++ This selects the MediaTek(R) SPI bus driver.
++ If you want to use MediaTek(R) SPI interface,
++ say Y or M here.If you are not sure, say N.
++ SPI drivers for Mediatek mt65XX series ARM SoCs.
++
+ config SPI_OC_TINY
+ tristate "OpenCores tiny SPI"
+ depends on GPIOLIB
+diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
+index d8cbf65..ab332ef 100644
+--- a/drivers/spi/Makefile
++++ b/drivers/spi/Makefile
+@@ -48,6 +48,7 @@ obj-$(CONFIG_SPI_MESON_SPIFC) += spi-meson-spifc.o
+ obj-$(CONFIG_SPI_MPC512x_PSC) += spi-mpc512x-psc.o
+ obj-$(CONFIG_SPI_MPC52xx_PSC) += spi-mpc52xx-psc.o
+ obj-$(CONFIG_SPI_MPC52xx) += spi-mpc52xx.o
++obj-$(CONFIG_SPI_MT65XX) += spi-mt65xx.o
+ obj-$(CONFIG_SPI_MXS) += spi-mxs.o
+ obj-$(CONFIG_SPI_NUC900) += spi-nuc900.o
+ obj-$(CONFIG_SPI_OC_TINY) += spi-oc-tiny.o
+diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c
+new file mode 100644
+index 0000000..92c119d
+--- /dev/null
++++ b/drivers/spi/spi-mt65xx.c
+@@ -0,0 +1,622 @@
++/*
++ * Copyright (c) 2015 MediaTek Inc.
++ * Author: Leilk Liu <leilk.liu@mediatek.com>
++ *
++ * 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.
++ */
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/device.h>
++#include <linux/ioport.h>
++#include <linux/errno.h>
++#include <linux/spi/spi.h>
++#include <linux/workqueue.h>
++#include <linux/dma-mapping.h>
++#include <linux/platform_device.h>
++#include <linux/interrupt.h>
++#include <linux/irqreturn.h>
++#include <linux/types.h>
++#include <linux/delay.h>
++#include <linux/clk.h>
++#include <linux/err.h>
++#include <linux/io.h>
++#include <linux/sched.h>
++#include <linux/of.h>
++#include <linux/of_irq.h>
++#include <linux/of_address.h>
++#include <linux/kernel.h>
++#include <linux/spi/spi_bitbang.h>
++#include <linux/gpio.h>
++#include <linux/module.h>
++#include <linux/of_gpio.h>
++
++#define SPI_CFG0_REG 0x0000
++#define SPI_CFG1_REG 0x0004
++#define SPI_TX_SRC_REG 0x0008
++#define SPI_RX_DST_REG 0x000c
++#define SPI_CMD_REG 0x0018
++#define SPI_STATUS0_REG 0x001c
++#define SPI_PAD_SEL_REG 0x0024
++
++#define SPI_CFG0_SCK_HIGH_OFFSET 0
++#define SPI_CFG0_SCK_LOW_OFFSET 8
++#define SPI_CFG0_CS_HOLD_OFFSET 16
++#define SPI_CFG0_CS_SETUP_OFFSET 24
++
++#define SPI_CFG0_SCK_HIGH_MASK 0xff
++#define SPI_CFG0_SCK_LOW_MASK 0xff00
++#define SPI_CFG0_CS_HOLD_MASK 0xff0000
++#define SPI_CFG0_CS_SETUP_MASK 0xff000000
++
++#define SPI_CFG1_CS_IDLE_OFFSET 0
++#define SPI_CFG1_PACKET_LOOP_OFFSET 8
++#define SPI_CFG1_PACKET_LENGTH_OFFSET 16
++#define SPI_CFG1_GET_TICK_DLY_OFFSET 30
++
++#define SPI_CFG1_CS_IDLE_MASK 0xff
++#define SPI_CFG1_PACKET_LOOP_MASK 0xff00
++#define SPI_CFG1_PACKET_LENGTH_MASK 0x3ff0000
++#define SPI_CFG1_GET_TICK_DLY_MASK 0xc0000000
++
++#define SPI_CMD_ACT_OFFSET 0
++#define SPI_CMD_RESUME_OFFSET 1
++#define SPI_CMD_RST_OFFSET 2
++#define SPI_CMD_PAUSE_EN_OFFSET 4
++#define SPI_CMD_DEASSERT_OFFSET 5
++#define SPI_CMD_CPHA_OFFSET 8
++#define SPI_CMD_CPOL_OFFSET 9
++#define SPI_CMD_RX_DMA_OFFSET 10
++#define SPI_CMD_TX_DMA_OFFSET 11
++#define SPI_CMD_TXMSBF_OFFSET 12
++#define SPI_CMD_RXMSBF_OFFSET 13
++#define SPI_CMD_RX_ENDIAN_OFFSET 14
++#define SPI_CMD_TX_ENDIAN_OFFSET 15
++#define SPI_CMD_FINISH_IE_OFFSET 16
++#define SPI_CMD_PAUSE_IE_OFFSET 17
++
++#define SPI_CMD_RESUME_MASK 0x2
++#define SPI_CMD_RST_MASK 0x4
++#define SPI_CMD_PAUSE_EN_MASK 0x10
++#define SPI_CMD_DEASSERT_MASK 0x20
++#define SPI_CMD_CPHA_MASK 0x100
++#define SPI_CMD_CPOL_MASK 0x200
++#define SPI_CMD_RX_DMA_MASK 0x400
++#define SPI_CMD_TX_DMA_MASK 0x800
++#define SPI_CMD_TXMSBF_MASK 0x1000
++#define SPI_CMD_RXMSBF_MASK 0x2000
++#define SPI_CMD_RX_ENDIAN_MASK 0x4000
++#define SPI_CMD_TX_ENDIAN_MASK 0x8000
++#define SPI_CMD_FINISH_IE_MASK 0x10000
++
++#define COMPAT_MT6589 (0x1 << 0)
++#define COMPAT_MT8173 (0x1 << 1)
++
++#define MT8173_MAX_PAD_SEL 3
++
++#define IDLE 0
++#define INPROGRESS 1
++#define PAUSED 2
++
++#define PACKET_SIZE 1024
++
++struct mtk_chip_config {
++ u32 setuptime;
++ u32 holdtime;
++ u32 high_time;
++ u32 low_time;
++ u32 cs_idletime;
++ u32 tx_mlsb;
++ u32 rx_mlsb;
++ u32 tx_endian;
++ u32 rx_endian;
++ u32 pause;
++ u32 finish_intr;
++ u32 deassert;
++ u32 tckdly;
++};
++
++struct mtk_spi_ddata {
++ struct spi_bitbang bitbang;
++ void __iomem *base;
++ u32 irq;
++ u32 state;
++ u32 platform_compat;
++ u32 pad_sel;
++ struct clk *clk;
++
++ const u8 *tx_buf;
++ u8 *rx_buf;
++ u32 tx_len, rx_len;
++ struct completion done;
++};
++
++/*
++ * A piece of default chip info unless the platform
++ * supplies it.
++ */
++static const struct mtk_chip_config mtk_default_chip_info = {
++ .setuptime = 10,
++ .holdtime = 12,
++ .high_time = 6,
++ .low_time = 6,
++ .cs_idletime = 12,
++ .rx_mlsb = 1,
++ .tx_mlsb = 1,
++ .tx_endian = 0,
++ .rx_endian = 0,
++ .pause = 0,
++ .finish_intr = 1,
++ .deassert = 0,
++ .tckdly = 0,
++};
++
++static const struct of_device_id mtk_spi_of_match[] = {
++ { .compatible = "mediatek,mt6589-spi", .data = (void *)COMPAT_MT6589},
++ { .compatible = "mediatek,mt8173-spi", .data = (void *)COMPAT_MT8173},
++ {}
++};
++MODULE_DEVICE_TABLE(of, mtk_spi_of_match);
++
++static void mtk_spi_reset(struct mtk_spi_ddata *mdata)
++{
++ u32 reg_val;
++
++ /*set the software reset bit in SPI_CMD_REG.*/
++ reg_val = readl(mdata->base + SPI_CMD_REG);
++ reg_val &= ~SPI_CMD_RST_MASK;
++ reg_val |= 1 << SPI_CMD_RST_OFFSET;
++ writel(reg_val, mdata->base + SPI_CMD_REG);
++ reg_val = readl(mdata->base + SPI_CMD_REG);
++ reg_val &= ~SPI_CMD_RST_MASK;
++ writel(reg_val, mdata->base + SPI_CMD_REG);
++}
++
++static void mtk_set_pause_bit(struct mtk_spi_ddata *mdata)
++{
++ u32 reg_val;
++
++ reg_val = readl(mdata->base + SPI_CMD_REG);
++ reg_val |= 1 << SPI_CMD_PAUSE_EN_OFFSET;
++ reg_val |= 1 << SPI_CMD_PAUSE_IE_OFFSET;
++ writel(reg_val, mdata->base + SPI_CMD_REG);
++}
++
++static void mtk_clear_pause_bit(struct mtk_spi_ddata *mdata)
++{
++ u32 reg_val;
++
++ reg_val = readl(mdata->base + SPI_CMD_REG);
++ reg_val &= ~SPI_CMD_PAUSE_EN_MASK;
++ writel(reg_val, mdata->base + SPI_CMD_REG);
++}
++
++static int mtk_spi_config(struct mtk_spi_ddata *mdata,
++ struct mtk_chip_config *chip_config)
++{
++ u32 reg_val;
++
++ /* set the timing */
++ reg_val = readl(mdata->base + SPI_CFG0_REG);
++ reg_val &= ~(SPI_CFG0_SCK_HIGH_MASK | SPI_CFG0_SCK_LOW_MASK);
++ reg_val &= ~(SPI_CFG0_CS_HOLD_MASK | SPI_CFG0_CS_SETUP_MASK);
++ reg_val |= ((chip_config->high_time - 1) << SPI_CFG0_SCK_HIGH_OFFSET);
++ reg_val |= ((chip_config->low_time - 1) << SPI_CFG0_SCK_LOW_OFFSET);
++ reg_val |= ((chip_config->holdtime - 1) << SPI_CFG0_CS_HOLD_OFFSET);
++ reg_val |= ((chip_config->setuptime - 1) << SPI_CFG0_CS_SETUP_OFFSET);
++ writel(reg_val, mdata->base + SPI_CFG0_REG);
++
++ reg_val = readl(mdata->base + SPI_CFG1_REG);
++ reg_val &= ~SPI_CFG1_CS_IDLE_MASK;
++ reg_val |= ((chip_config->cs_idletime - 1) << SPI_CFG1_CS_IDLE_OFFSET);
++ reg_val &= ~SPI_CFG1_GET_TICK_DLY_MASK;
++ reg_val |= ((chip_config->tckdly) << SPI_CFG1_GET_TICK_DLY_OFFSET);
++ writel(reg_val, mdata->base + SPI_CFG1_REG);
++
++ /* set the mlsbx and mlsbtx */
++ reg_val = readl(mdata->base + SPI_CMD_REG);
++ reg_val &= ~(SPI_CMD_TX_ENDIAN_MASK | SPI_CMD_RX_ENDIAN_MASK);
++ reg_val &= ~(SPI_CMD_TXMSBF_MASK | SPI_CMD_RXMSBF_MASK);
++ reg_val |= (chip_config->tx_mlsb << SPI_CMD_TXMSBF_OFFSET);
++ reg_val |= (chip_config->rx_mlsb << SPI_CMD_RXMSBF_OFFSET);
++ reg_val |= (chip_config->tx_endian << SPI_CMD_TX_ENDIAN_OFFSET);
++ reg_val |= (chip_config->rx_endian << SPI_CMD_RX_ENDIAN_OFFSET);
++ writel(reg_val, mdata->base + SPI_CMD_REG);
++
++ /* set finish and pause interrupt always enable */
++ reg_val = readl(mdata->base + SPI_CMD_REG);
++ reg_val &= ~SPI_CMD_FINISH_IE_MASK;
++ reg_val |= (chip_config->finish_intr << SPI_CMD_FINISH_IE_OFFSET);
++ writel(reg_val, mdata->base + SPI_CMD_REG);
++
++ reg_val = readl(mdata->base + SPI_CMD_REG);
++ reg_val |= 1 << SPI_CMD_TX_DMA_OFFSET;
++ reg_val |= 1 << SPI_CMD_RX_DMA_OFFSET;
++ writel(reg_val, mdata->base + SPI_CMD_REG);
++
++ /* set deassert mode */
++ reg_val = readl(mdata->base + SPI_CMD_REG);
++ reg_val &= ~SPI_CMD_DEASSERT_MASK;
++ reg_val |= (chip_config->deassert << SPI_CMD_DEASSERT_OFFSET);
++ writel(reg_val, mdata->base + SPI_CMD_REG);
++
++ /* pad select */
++ if (mdata->platform_compat & COMPAT_MT8173)
++ writel(mdata->pad_sel, mdata->base + SPI_PAD_SEL_REG);
++
++ return 0;
++}
++
++static int mtk_spi_setup_transfer(struct spi_device *spi,
++ struct spi_transfer *t)
++{
++ u32 reg_val;
++ struct spi_master *master = spi->master;
++ struct mtk_spi_ddata *mdata = spi_master_get_devdata(master);
++ struct spi_message *m = master->cur_msg;
++ struct mtk_chip_config *chip_config;
++
++ u8 cpha = spi->mode & SPI_CPHA ? 1 : 0;
++ u8 cpol = spi->mode & SPI_CPOL ? 1 : 0;
++
++ reg_val = readl(mdata->base + SPI_CMD_REG);
++ reg_val &= ~(SPI_CMD_CPHA_MASK | SPI_CMD_CPOL_MASK);
++ reg_val |= (cpha << SPI_CMD_CPHA_OFFSET);
++ reg_val |= (cpol << SPI_CMD_CPOL_OFFSET);
++ writel(reg_val, mdata->base + SPI_CMD_REG);
++
++ if (t->cs_change) {
++ if (!(list_is_last(&t->transfer_list, &m->transfers)))
++ mdata->state = IDLE;
++ } else {
++ mdata->state = IDLE;
++ mtk_spi_reset(mdata);
++ }
++
++ chip_config = (struct mtk_chip_config *)spi->controller_data;
++ if (!chip_config) {
++ chip_config = (void *)&mtk_default_chip_info;
++ spi->controller_data = chip_config;
++ mdata->state = IDLE;
++ }
++
++ mtk_spi_config(mdata, chip_config);
++
++ return 0;
++}
++
++static void mtk_spi_chipselect(struct spi_device *spi, int is_on)
++{
++ struct mtk_spi_ddata *mdata = spi_master_get_devdata(spi->master);
++
++ switch (is_on) {
++ case BITBANG_CS_ACTIVE:
++ mtk_set_pause_bit(mdata);
++ break;
++ case BITBANG_CS_INACTIVE:
++ mtk_clear_pause_bit(mdata);
++ break;
++ }
++}
++
++static void mtk_spi_start_transfer(struct mtk_spi_ddata *mdata)
++{
++ u32 reg_val;
++
++ reg_val = readl(mdata->base + SPI_CMD_REG);
++ reg_val |= 1 << SPI_CMD_ACT_OFFSET;
++ writel(reg_val, mdata->base + SPI_CMD_REG);
++}
++
++static void mtk_spi_resume_transfer(struct mtk_spi_ddata *mdata)
++{
++ u32 reg_val;
++
++ reg_val = readl(mdata->base + SPI_CMD_REG);
++ reg_val &= ~SPI_CMD_RESUME_MASK;
++ reg_val |= 1 << SPI_CMD_RESUME_OFFSET;
++ writel(reg_val, mdata->base + SPI_CMD_REG);
++}
++
++static int mtk_spi_setup_packet(struct mtk_spi_ddata *mdata,
++ struct spi_transfer *xfer)
++{
++ struct device *dev = &mdata->bitbang.master->dev;
++ u32 packet_size, packet_loop, reg_val;
++
++ packet_size = min_t(unsigned, xfer->len, PACKET_SIZE);
++
++ /* mtk hw has the restriction that xfer len must be a multiple of 1024,
++ * when it is greater than 1024bytes.
++ */
++ if (xfer->len % packet_size) {
++ dev_err(dev, "ERROR!The lens must be a multiple of %d, your len %d\n",
++ PACKET_SIZE, xfer->len);
++ return -EINVAL;
++ }
++
++ packet_loop = xfer->len / packet_size;
++
++ reg_val = readl(mdata->base + SPI_CFG1_REG);
++ reg_val &= ~(SPI_CFG1_PACKET_LENGTH_MASK + SPI_CFG1_PACKET_LOOP_MASK);
++ reg_val |= (packet_size - 1) << SPI_CFG1_PACKET_LENGTH_OFFSET;
++ reg_val |= (packet_loop - 1) << SPI_CFG1_PACKET_LOOP_OFFSET;
++ writel(reg_val, mdata->base + SPI_CFG1_REG);
++
++ return 0;
++}
++
++static int mtk_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *xfer)
++{
++ struct spi_master *master = spi->master;
++ struct mtk_spi_ddata *mdata = spi_master_get_devdata(master);
++ struct device *dev = &mdata->bitbang.master->dev;
++ int cmd, ret;
++
++ /* mtk spi hw tx/rx have 4bytes aligned restriction,
++ * so kmalloc tx/rx buffer to workaround here.
++ */
++ mdata->tx_buf = NULL;
++ mdata->rx_buf = NULL;
++ if (xfer->tx_buf) {
++ mdata->tx_buf = kmalloc(xfer->len, GFP_KERNEL);
++ if (!mdata->tx_buf) {
++ dev_err(dev, "malloc tx_buf failed.\n");
++ ret = -ENOMEM;
++ goto err_free;
++ }
++ memcpy((void *)mdata->tx_buf, xfer->tx_buf, xfer->len);
++ }
++ if (xfer->rx_buf) {
++ mdata->rx_buf = kmalloc(xfer->len, GFP_KERNEL);
++ if (!mdata->rx_buf) {
++ dev_err(dev, "malloc rx_buf failed.\n");
++ ret = -ENOMEM;
++ goto err_free;
++ }
++ }
++
++ reinit_completion(&mdata->done);
++
++ xfer->tx_dma = DMA_ERROR_CODE;
++ xfer->rx_dma = DMA_ERROR_CODE;
++ if (xfer->tx_buf) {
++ xfer->tx_dma = dma_map_single(dev, (void *)mdata->tx_buf,
++ xfer->len, DMA_TO_DEVICE);
++ if (dma_mapping_error(dev, xfer->tx_dma)) {
++ dev_err(dev, "dma mapping tx_buf error.\n");
++ ret = -ENOMEM;
++ goto err_free;
++ }
++ }
++ if (xfer->rx_buf) {
++ xfer->rx_dma = dma_map_single(dev, mdata->rx_buf,
++ xfer->len, DMA_FROM_DEVICE);
++ if (dma_mapping_error(dev, xfer->rx_dma)) {
++ if (xfer->tx_buf)
++ dma_unmap_single(dev, xfer->tx_dma,
++ xfer->len, DMA_TO_DEVICE);
++ dev_err(dev, "dma mapping rx_buf error.\n");
++ ret = -ENOMEM;
++ goto err_free;
++ }
++ }
++
++ ret = mtk_spi_setup_packet(mdata, xfer);
++ if (ret != 0)
++ goto err_free;
++
++ /* Here is mt8173 HW issue: RX must enable TX, then TX transfer
++ * dummy data; TX don't need to enable RX. so enable TX dma for
++ * RX to workaround.
++ */
++ cmd = readl(mdata->base + SPI_CMD_REG);
++ if (xfer->tx_buf || (mdata->platform_compat & COMPAT_MT8173))
++ cmd |= 1 << SPI_CMD_TX_DMA_OFFSET;
++ if (xfer->rx_buf)
++ cmd |= 1 << SPI_CMD_RX_DMA_OFFSET;
++ writel(cmd, mdata->base + SPI_CMD_REG);
++
++ /* set up the DMA bus address */
++ if (xfer->tx_dma != DMA_ERROR_CODE)
++ writel(cpu_to_le32(xfer->tx_dma), mdata->base + SPI_TX_SRC_REG);
++ if (xfer->rx_dma != DMA_ERROR_CODE)
++ writel(cpu_to_le32(xfer->rx_dma), mdata->base + SPI_RX_DST_REG);
++
++ if (mdata->state == IDLE)
++ mtk_spi_start_transfer(mdata);
++ else if (mdata->state == PAUSED)
++ mtk_spi_resume_transfer(mdata);
++ else
++ mdata->state = INPROGRESS;
++
++ wait_for_completion(&mdata->done);
++
++ if (xfer->tx_dma != DMA_ERROR_CODE) {
++ dma_unmap_single(dev, xfer->tx_dma, xfer->len, DMA_TO_DEVICE);
++ xfer->tx_dma = DMA_ERROR_CODE;
++ }
++ if (xfer->rx_dma != DMA_ERROR_CODE) {
++ dma_unmap_single(dev, xfer->rx_dma, xfer->len, DMA_FROM_DEVICE);
++ xfer->rx_dma = DMA_ERROR_CODE;
++ }
++
++ /* spi disable dma */
++ cmd = readl(mdata->base + SPI_CMD_REG);
++ cmd &= ~SPI_CMD_TX_DMA_MASK;
++ cmd &= ~SPI_CMD_RX_DMA_MASK;
++ writel(cmd, mdata->base + SPI_CMD_REG);
++
++ if (xfer->rx_buf)
++ memcpy(xfer->rx_buf, mdata->rx_buf, xfer->len);
++
++ ret = xfer->len;
++
++err_free:
++ kfree(mdata->tx_buf);
++ kfree(mdata->rx_buf);
++ return ret;
++}
++
++static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id)
++{
++ struct mtk_spi_ddata *mdata = dev_id;
++ u32 reg_val;
++
++ reg_val = readl(mdata->base + SPI_STATUS0_REG);
++ if (reg_val & 0x2)
++ mdata->state = PAUSED;
++ else
++ mdata->state = IDLE;
++ complete(&mdata->done);
++
++ return IRQ_HANDLED;
++}
++
++static unsigned long mtk_get_device_prop(struct platform_device *pdev)
++{
++ const struct of_device_id *match;
++
++ match = of_match_node(mtk_spi_of_match, pdev->dev.of_node);
++ return (unsigned long)match->data;
++}
++
++static int mtk_spi_probe(struct platform_device *pdev)
++{
++ struct spi_master *master;
++ struct mtk_spi_ddata *mdata;
++ struct resource *res;
++ int ret;
++
++ master = spi_alloc_master(&pdev->dev, sizeof(struct mtk_spi_ddata));
++ if (!master) {
++ dev_err(&pdev->dev, "failed to alloc spi master\n");
++ return -ENOMEM;
++ }
++
++ platform_set_drvdata(pdev, master);
++
++ master->dev.of_node = pdev->dev.of_node;
++ master->bus_num = pdev->id;
++ master->num_chipselect = 1;
++ master->mode_bits = SPI_CPOL | SPI_CPHA;
++
++ mdata = spi_master_get_devdata(master);
++
++ mdata->bitbang.master = master;
++ mdata->bitbang.chipselect = mtk_spi_chipselect;
++ mdata->bitbang.setup_transfer = mtk_spi_setup_transfer;
++ mdata->bitbang.txrx_bufs = mtk_spi_txrx_bufs;
++ mdata->platform_compat = mtk_get_device_prop(pdev);
++
++ if (mdata->platform_compat & COMPAT_MT8173) {
++ ret = of_property_read_u32(pdev->dev.of_node, "pad-select",
++ &mdata->pad_sel);
++ if (ret) {
++ dev_err(&pdev->dev, "failed to read pad select: %d\n",
++ ret);
++ goto err;
++ }
++
++ if (mdata->pad_sel > MT8173_MAX_PAD_SEL) {
++ dev_err(&pdev->dev, "wrong pad-select: %u\n",
++ mdata->pad_sel);
++ goto err;
++ }
++ }
++
++ init_completion(&mdata->done);
++
++ mdata->clk = devm_clk_get(&pdev->dev, "main");
++ if (IS_ERR(mdata->clk)) {
++ ret = PTR_ERR(mdata->clk);
++ dev_err(&pdev->dev, "failed to get clock: %d\n", ret);
++ goto err;
++ }
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!res) {
++ ret = -ENODEV;
++ dev_err(&pdev->dev, "failed to determine base address\n");
++ goto err;
++ }
++
++ mdata->base = devm_ioremap_resource(&pdev->dev, res);
++ if (IS_ERR(mdata->base)) {
++ ret = PTR_ERR(mdata->base);
++ goto err;
++ }
++
++ ret = platform_get_irq(pdev, 0);
++ if (ret < 0) {
++ dev_err(&pdev->dev, "failed to get irq (%d)\n", ret);
++ goto err;
++ }
++
++ mdata->irq = ret;
++
++ if (!pdev->dev.dma_mask)
++ pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
++
++ mdata->bitbang.master->dev.dma_mask = pdev->dev.dma_mask;
++
++ ret = clk_prepare_enable(mdata->clk);
++ if (ret < 0) {
++ dev_err(&pdev->dev, "failed to enable clock (%d)\n", ret);
++ goto err;
++ }
++
++ ret = devm_request_irq(&pdev->dev, mdata->irq, mtk_spi_interrupt,
++ IRQF_TRIGGER_NONE, dev_name(&pdev->dev), mdata);
++ if (ret) {
++ dev_err(&pdev->dev, "failed to register irq (%d)\n", ret);
++ goto err_disable_clk;
++ }
++
++ ret = spi_bitbang_start(&mdata->bitbang);
++ if (ret) {
++ dev_err(&pdev->dev, "spi_bitbang_start failed (%d)\n", ret);
++err_disable_clk:
++ clk_disable_unprepare(mdata->clk);
++err:
++ spi_master_put(master);
++ }
++
++ return ret;
++}
++
++static int mtk_spi_remove(struct platform_device *pdev)
++{
++ struct spi_master *master = platform_get_drvdata(pdev);
++ struct mtk_spi_ddata *mdata = spi_master_get_devdata(master);
++
++ spi_bitbang_stop(&mdata->bitbang);
++ mtk_spi_reset(mdata);
++ clk_disable_unprepare(mdata->clk);
++ spi_master_put(master);
++
++ return 0;
++}
++
++struct platform_driver mtk_spi_driver = {
++ .driver = {
++ .name = "mtk-spi",
++ .of_match_table = mtk_spi_of_match,
++ },
++ .probe = mtk_spi_probe,
++ .remove = mtk_spi_remove,
++};
++
++module_platform_driver(mtk_spi_driver);
++
++MODULE_DESCRIPTION("MTK SPI Controller driver");
++MODULE_AUTHOR("Leilk Liu <leilk.liu@mediatek.com>");
++MODULE_LICENSE("GPL v2");
++MODULE_ALIAS("platform: mtk_spi");
+--
+1.7.10.4
+