LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
* [PATCH v5]: clk: Add common clock support for Mediatek MT8135 and MT8173
@ 2015-02-09 10:47 Sascha Hauer
  2015-02-09 10:47 ` [PATCH 01/13] clk: dts: mediatek: add Mediatek MT8135 clock bindings Sascha Hauer
                   ` (12 more replies)
  0 siblings, 13 replies; 27+ messages in thread
From: Sascha Hauer @ 2015-02-09 10:47 UTC (permalink / raw)
  To: Matthias Brugger
  Cc: linux-arm-kernel, linux-kernel, Rob Herring, Eddie Huang,
	Lee Jones, Yingjoe Chen (陳英洲),
	Henry Chen, YH Chen (陳昱豪),
	kernel, Mike Turquette

This patchset contains the initial common clock support for Mediatek SoCs.
Mediatek SoC's clock architecture comprises of various PLLs, dividers, muxes and clock gates.

This patchset also contains a basic clock support for Mediatek MT8135 and MT8173.

Also included is now my PMIC wrapper series as of v3. Since it now depends on
the clock drivers I can no longer post it independenty.

This driver is based on 3.19-rc1 + MT8135 and MT8173 basic support.

Changes in v2:
- Re-ordered patchset. Fold include/dt-bindings and DT document in 1st patch.

Changes in v3:
- Rebase to 3.19-rc1.
- Refine code. Remove unneed functions, debug logs and comments, and fine tune error logs.

Changes in v4:
- Support MT8173 platform.
- Re-ordered patchset. driver/clk/Makefile in 2nd patch.
- Extract the common part definition(mtk_gate/mtk_pll/mtk_mux) from clk-mt8135.c/clk-mt8173.c to clk-mtk.c.
- Refine code. Rmove unnessacary debug information and unsed defines, add prefix "mtk_" for static functions.
- Remove flag CLK_IGNORE_UNUSED and set flag CLK_SET_RATE_PARENT on gate/mux/fixed-factor.
- Use spin_lock_irqsave(&clk_ops_lock, flags) instead of mtk_clk_lock.
- Example above include a node for the clock controller itself, followed by the i2c controller example above.

Changes in v5:
- Add reset controller support for pericfg/infracfg
- Use regmap for the gates
- remove now unnecessary spinlock for the gates
- Add PMIC wrapper support as of v3

Sascha


^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH 01/13] clk: dts: mediatek: add Mediatek MT8135 clock bindings
  2015-02-09 10:47 [PATCH v5]: clk: Add common clock support for Mediatek MT8135 and MT8173 Sascha Hauer
@ 2015-02-09 10:47 ` Sascha Hauer
  2015-02-09 13:35   ` Philipp Zabel
  2015-02-09 10:47 ` [PATCH 02/13] clk: mediatek: Add initial common clock support for Mediatek SoCs Sascha Hauer
                   ` (11 subsequent siblings)
  12 siblings, 1 reply; 27+ messages in thread
From: Sascha Hauer @ 2015-02-09 10:47 UTC (permalink / raw)
  To: Matthias Brugger
  Cc: linux-arm-kernel, linux-kernel, Rob Herring, Eddie Huang,
	Lee Jones, Yingjoe Chen (陳英洲),
	Henry Chen, YH Chen (陳昱豪),
	kernel, Mike Turquette, James Liao, Sascha Hauer

From: James Liao <jamesjj.liao@mediatek.com>

Document the device-tree binding of Mediatek MT8135 SoC, including
TOPCKGEN, PLLs, INFRA and PERI clock controller.

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>
---
 .../bindings/clock/mediatek,mt8135-clock.txt       |  44 +++++
 include/dt-bindings/clock/mt8135-clk.h             | 190 +++++++++++++++++++++
 2 files changed, 234 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/mediatek,mt8135-clock.txt
 create mode 100644 include/dt-bindings/clock/mt8135-clk.h

diff --git a/Documentation/devicetree/bindings/clock/mediatek,mt8135-clock.txt b/Documentation/devicetree/bindings/clock/mediatek,mt8135-clock.txt
new file mode 100644
index 0000000..1e3566f
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/mediatek,mt8135-clock.txt
@@ -0,0 +1,44 @@
+Mediatek MT8135 Clock Controller
+
+This binding uses the common clock binding:
+Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+The Mediatek MT8135 clock controller generates and supplies clock to various
+controllers within Mediatek MT8135 SoC.
+
+Required Properties:
+
+- compatible: should be one of following:
+	- "mediatek,mt8135-topckgen" : for topckgen clock controller of MT8135.
+	- "mediatek,mt8135-apmixedsys" : for apmixed_sys (PLLs) of MT8135.
+	- "mediatek,mt8135-infracfg" : for infra_sys clock controller of MT8135.
+	- "mediatek,mt8135-pericfg" : for peri_sys clock controller of MT8135.
+
+- reg: physical base address of the controller and length of memory mapped
+  region.
+
+- #clock-cells: should be 1.
+
+All available clocks are defined as preprocessor macros in
+dt-bindings/clock/mt8135-clk.h header and can be used in device tree sources.
+
+Example: I2C controller node that consumes the clock generated by the clock
+  controller (refer to the standard clock bindings for information about
+  "clocks" and "clock-names" properties):
+
+	pericfg: pericfg@10003000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "mediatek,mt8135-pericfg";
+		reg = <0 0x10003000 0 0x1000>;
+		#clock-cells = <1>;
+	};
+
+	i2c0: i2c@1100d000 {
+		compatible = "mediatek,mt8135-i2c", "mediatek,mt6589-i2c";
+		reg = <0 0x1100d000 0 0x70>, <0 0x11000300 0 0x80>;
+		interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_LOW>;
+		clock-div = <16>;
+		clocks = <&pericfg PERI_I2C0_CK>, <&pericfg PERI_AP_DMA_CK>;
+		clock-names = "main", "dma";
+	};
diff --git a/include/dt-bindings/clock/mt8135-clk.h b/include/dt-bindings/clock/mt8135-clk.h
new file mode 100644
index 0000000..8aea762
--- /dev/null
+++ b/include/dt-bindings/clock/mt8135-clk.h
@@ -0,0 +1,190 @@
+/*
+ * 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 TOP_DSI0_LNTC_DSICLK	1
+#define TOP_HDMITX_CLKDIG_CTS	2
+#define TOP_CLKPH_MCK		3
+#define TOP_CPUM_TCK_IN		4
+#define TOP_MAINPLL_806M	5
+#define TOP_MAINPLL_537P3M	6
+#define TOP_MAINPLL_322P4M	7
+#define TOP_MAINPLL_230P3M	8
+#define TOP_UNIVPLL_624M	9
+#define TOP_UNIVPLL_416M	10
+#define TOP_UNIVPLL_249P6M	11
+#define TOP_UNIVPLL_178P3M	12
+#define TOP_UNIVPLL_48M		13
+#define TOP_MMPLL_D2		14
+#define TOP_MMPLL_D3		15
+#define TOP_MMPLL_D5		16
+#define TOP_MMPLL_D7		17
+#define TOP_MMPLL_D4		18
+#define TOP_MMPLL_D6		19
+#define TOP_SYSPLL_D2		20
+#define TOP_SYSPLL_D4		21
+#define TOP_SYSPLL_D6		22
+#define TOP_SYSPLL_D8		23
+#define TOP_SYSPLL_D10		24
+#define TOP_SYSPLL_D12		25
+#define TOP_SYSPLL_D16		26
+#define TOP_SYSPLL_D24		27
+#define TOP_SYSPLL_D3		28
+#define TOP_SYSPLL_D2P5		29
+#define TOP_SYSPLL_D5		30
+#define TOP_SYSPLL_D3P5		31
+#define TOP_UNIVPLL1_D2		32
+#define TOP_UNIVPLL1_D4		33
+#define TOP_UNIVPLL1_D6		34
+#define TOP_UNIVPLL1_D8		35
+#define TOP_UNIVPLL1_D10	36
+#define TOP_UNIVPLL2_D2		37
+#define TOP_UNIVPLL2_D4		38
+#define TOP_UNIVPLL2_D6		39
+#define TOP_UNIVPLL2_D8		40
+#define TOP_UNIVPLL_D3		41
+#define TOP_UNIVPLL_D5		42
+#define TOP_UNIVPLL_D7		43
+#define TOP_UNIVPLL_D10		44
+#define TOP_UNIVPLL_D26		45
+#define TOP_APLL_CK		46
+#define TOP_APLL_D4		47
+#define TOP_APLL_D8		48
+#define TOP_APLL_D16		49
+#define TOP_APLL_D24		50
+#define TOP_LVDSPLL_D2		51
+#define TOP_LVDSPLL_D4		52
+#define TOP_LVDSPLL_D8		53
+#define TOP_LVDSTX_CLKDIG_CT	54
+#define TOP_VPLL_DPIX_CK	55
+#define TOP_TVHDMI_H_CK		56
+#define TOP_HDMITX_CLKDIG_D2	57
+#define TOP_HDMITX_CLKDIG_D3	58
+#define TOP_TVHDMI_D2		59
+#define TOP_TVHDMI_D4		60
+#define TOP_MEMPLL_MCK_D4	61
+#define TOP_AXI_SEL		62
+#define TOP_SMI_SEL		63
+#define TOP_MFG_SEL		64
+#define TOP_IRDA_SEL		65
+#define TOP_CAM_SEL		66
+#define TOP_AUD_INTBUS_SEL	67
+#define TOP_JPG_SEL		68
+#define TOP_DISP_SEL		69
+#define TOP_MSDC30_1_SEL	70
+#define TOP_MSDC30_2_SEL	71
+#define TOP_MSDC30_3_SEL	72
+#define TOP_MSDC30_4_SEL	73
+#define TOP_USB20_SEL		74
+#define TOP_VENC_SEL		75
+#define TOP_SPI_SEL		76
+#define TOP_UART_SEL		77
+#define TOP_MEM_SEL		78
+#define TOP_CAMTG_SEL		79
+#define TOP_AUDIO_SEL		80
+#define TOP_FIX_SEL		81
+#define TOP_VDEC_SEL		82
+#define TOP_DDRPHYCFG_SEL	83
+#define TOP_DPILVDS_SEL		84
+#define TOP_PMICSPI_SEL		85
+#define TOP_MSDC30_0_SEL	86
+#define TOP_SMI_MFG_AS_SEL	87
+#define TOP_GCPU_SEL		88
+#define TOP_DPI1_SEL		89
+#define TOP_CCI_SEL		90
+#define TOP_APLL_SEL		91
+#define TOP_HDMIPLL_SEL		92
+#define TOP_NR_CLK		93
+
+/* APMIXED_SYS */
+
+#define APMIXED_ARMPLL1		1
+#define APMIXED_ARMPLL2		2
+#define APMIXED_MAINPLL		3
+#define APMIXED_UNIVPLL		4
+#define APMIXED_MMPLL		5
+#define APMIXED_MSDCPLL		6
+#define APMIXED_TVDPLL		7
+#define APMIXED_LVDSPLL		8
+#define APMIXED_AUDPLL		9
+#define APMIXED_VDECPLL		10
+#define APMIXED_NR_CLK		11
+
+/* INFRA_SYS */
+
+#define INFRA_PMIC_WRAP_CK	1
+#define INFRA_PMICSPI_CK	2
+#define INFRA_CCIF1_AP_CTRL	3
+#define INFRA_CCIF0_AP_CTRL	4
+#define INFRA_KP_CK		5
+#define INFRA_CPUM_CK		6
+#define INFRA_M4U_CK		7
+#define INFRA_MFGAXI_CK		8
+#define INFRA_DEVAPC_CK		9
+#define INFRA_AUDIO_CK		10
+#define INFRA_MFG_BUS_CK	11
+#define INFRA_SMI_CK		12
+#define INFRA_DBGCLK_CK		13
+#define INFRA_NR_CLK		14
+
+/* PERI_SYS */
+
+#define PERI_I2C5_CK		1
+#define PERI_I2C4_CK		2
+#define PERI_I2C3_CK		3
+#define PERI_I2C2_CK		4
+#define PERI_I2C1_CK		5
+#define PERI_I2C0_CK		6
+#define PERI_UART3_CK		7
+#define PERI_UART2_CK		8
+#define PERI_UART1_CK		9
+#define PERI_UART0_CK		10
+#define PERI_IRDA_CK		11
+#define PERI_NLI_CK		12
+#define PERI_MD_HIF_CK		13
+#define PERI_AP_HIF_CK		14
+#define PERI_MSDC30_3_CK	15
+#define PERI_MSDC30_2_CK	16
+#define PERI_MSDC30_1_CK	17
+#define PERI_MSDC20_2_CK	18
+#define PERI_MSDC20_1_CK	19
+#define PERI_AP_DMA_CK		20
+#define PERI_USB1_CK		21
+#define PERI_USB0_CK		22
+#define PERI_PWM_CK		23
+#define PERI_PWM7_CK		24
+#define PERI_PWM6_CK		25
+#define PERI_PWM5_CK		26
+#define PERI_PWM4_CK		27
+#define PERI_PWM3_CK		28
+#define PERI_PWM2_CK		29
+#define PERI_PWM1_CK		30
+#define PERI_THERM_CK		31
+#define PERI_NFI_CK		32
+#define PERI_USBSLV_CK		33
+#define PERI_USB1_MCU_CK	34
+#define PERI_USB0_MCU_CK	35
+#define PERI_GCPU_CK		36
+#define PERI_FHCTL_CK		37
+#define PERI_SPI1_CK		38
+#define PERI_AUXADC_CK		39
+#define PERI_PERI_PWRAP_CK	40
+#define PERI_I2C6_CK		41
+#define PERI_NR_CLK		42
+
+#endif /* _DT_BINDINGS_CLK_MT8135_H */
-- 
2.1.4


^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH 02/13] clk: mediatek: Add initial common clock support for Mediatek SoCs.
  2015-02-09 10:47 [PATCH v5]: clk: Add common clock support for Mediatek MT8135 and MT8173 Sascha Hauer
  2015-02-09 10:47 ` [PATCH 01/13] clk: dts: mediatek: add Mediatek MT8135 clock bindings Sascha Hauer
@ 2015-02-09 10:47 ` Sascha Hauer
  2015-02-13  7:41   ` Tomasz Figa
  2015-02-09 10:47 ` [PATCH 03/13] clk: mediatek: Add reset controller support Sascha Hauer
                   ` (10 subsequent siblings)
  12 siblings, 1 reply; 27+ messages in thread
From: Sascha Hauer @ 2015-02-09 10:47 UTC (permalink / raw)
  To: Matthias Brugger
  Cc: linux-arm-kernel, linux-kernel, Rob Herring, Eddie Huang,
	Lee Jones, Yingjoe Chen (陳英洲),
	Henry Chen, YH Chen (陳昱豪),
	kernel, Mike Turquette, James Liao, Sascha Hauer

From: James Liao <jamesjj.liao@mediatek.com>

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  | 155 ++++++++++++++++++++++++++++++++++++++++
 drivers/clk/mediatek/clk-mtk.h  | 133 ++++++++++++++++++++++++++++++++++
 drivers/clk/mediatek/clk-pll.c  |  63 ++++++++++++++++
 drivers/clk/mediatek/clk-pll.h  |  52 ++++++++++++++
 8 files changed, 591 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
 create mode 100644 drivers/clk/mediatek/clk-pll.h

diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index d5fba5b..ce6c250 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -47,6 +47,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..a44dcbf
--- /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
+
+/*
+ * This is a private header file. DO NOT include it except clk-*.c.
+ */
+#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;
+};
+
+#define to_clk_gate(_hw) 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..479857c
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mtk.c
@@ -0,0 +1,155 @@
+/*
+ * 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"
+
+void mtk_init_factors(struct mtk_fixed_factor *clks, int num,
+		struct clk_onecell_data *clk_data)
+{
+	int i;
+	struct clk *clk;
+
+	for (i = 0; i < num; i++) {
+		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;
+	}
+}
+
+void mtk_init_clk_gates(struct regmap *regmap,
+		struct mtk_gate *clks, int num,
+		struct clk_onecell_data *clk_data)
+{
+	int i;
+	struct clk *clk;
+
+	for (i = 0; i < num; i++) {
+		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;
+		}
+
+		if (clk_data)
+			clk_data->clks[gate->id] = clk;
+	}
+}
+
+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(struct clk *), GFP_KERNEL);
+	if (!clk_data->clks) {
+		kfree(clk_data);
+		return NULL;
+	}
+
+	clk_data->clk_num = clk_num;
+
+	for (i = 0; i < clk_num; ++i)
+		clk_data->clks[i] = ERR_PTR(-ENOENT);
+
+	return clk_data;
+}
+
+struct clk *mtk_clk_register_mux(
+		const char *name,
+		const char **parent_names,
+		u8 num_parents,
+		void __iomem *base_addr,
+		u8 shift,
+		u8 width,
+		u8 gate_bit,
+		spinlock_t *lock)
+{
+	struct clk *clk;
+	struct clk_mux *mux;
+	struct clk_gate *gate = NULL;
+	struct clk_hw *gate_hw = NULL;
+	const struct clk_ops *gate_ops = NULL;
+	u32 mask = BIT(width) - 1;
+
+	mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL);
+	if (!mux)
+		return ERR_PTR(-ENOMEM);
+
+	mux->reg = base_addr;
+	mux->mask = mask;
+	mux->shift = shift;
+	mux->flags = 0;
+	mux->lock = lock;
+
+	if (gate_bit <= MAX_MUX_GATE_BIT) {
+		gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL);
+		if (!gate) {
+			kfree(mux);
+			return ERR_PTR(-ENOMEM);
+		}
+
+		gate->reg = base_addr;
+		gate->bit_idx = gate_bit;
+		gate->flags = CLK_GATE_SET_TO_DISABLE;
+		gate->lock = lock;
+
+		gate_hw = &gate->hw;
+		gate_ops = &clk_gate_ops;
+	}
+
+	clk = clk_register_composite(NULL, name, parent_names, num_parents,
+		&mux->hw, &clk_mux_ops,
+		NULL, NULL,
+		gate_hw, gate_ops,
+		CLK_SET_RATE_PARENT);
+
+	if (IS_ERR(clk)) {
+		kfree(gate);
+		kfree(mux);
+	}
+
+	return clk;
+}
diff --git a/drivers/clk/mediatek/clk-mtk.h b/drivers/clk/mediatek/clk-mtk.h
new file mode 100644
index 0000000..35cf9a3
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mtk.h
@@ -0,0 +1,133 @@
+/*
+ * 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
+
+/*
+ * This is a private header file. DO NOT include it except clk-*.c.
+ */
+
+#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)
+
+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_init_factors(struct mtk_fixed_factor *clks, int num,
+		struct clk_onecell_data *clk_data);
+
+struct mtk_mux {
+	int id;
+	const char *name;
+	uint32_t reg;
+	int shift;
+	int width;
+	int gate;
+	const char **parent_names;
+	int num_parents;
+};
+
+#define MUX(_id, _name, _parents, _reg, _shift, _width, _gate) {	\
+		.id = _id,						\
+		.name = _name,						\
+		.reg = _reg,						\
+		.shift = _shift,					\
+		.width = _width,					\
+		.gate = _gate,						\
+		.parent_names = (const char **)_parents,		\
+		.num_parents = ARRAY_SIZE(_parents),			\
+	}
+
+struct mtk_pll {
+	int id;
+	const char *name;
+	const char *parent_name;
+	uint32_t reg;
+	uint32_t pwr_reg;
+	uint32_t en_mask;
+	unsigned int flags;
+	const struct clk_ops *ops;
+};
+
+#define PLL(_id, _name, _parent, _reg, _pwr_reg, _en_mask, _flags, _ops) { \
+		.id = _id,						\
+		.name = _name,						\
+		.parent_name = _parent,					\
+		.reg = _reg,						\
+		.pwr_reg = _pwr_reg,					\
+		.en_mask = _en_mask,					\
+		.flags = _flags,					\
+		.ops = _ops,						\
+	}
+
+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;
+	struct mtk_gate_regs *regs;
+	int shift;
+	const struct clk_ops *ops;
+};
+
+#define GATE(_id, _name, _parent, _regs, _shift, _ops) {	\
+		.id = _id,					\
+		.name = _name,					\
+		.parent_name = _parent,				\
+		.regs = &_regs,					\
+		.shift = _shift,				\
+		.ops = _ops,					\
+	}
+
+void mtk_init_clk_gates(struct regmap *regmap,
+		struct mtk_gate *clks, int num,
+		struct clk_onecell_data *clk_data);
+
+struct clk_onecell_data *mtk_alloc_clk_data(unsigned int clk_num);
+
+struct clk *mtk_clk_register_mux(
+		const char *name,
+		const char **parent_names,
+		u8 num_parents,
+		void __iomem *base_addr,
+		u8 shift,
+		u8 width,
+		u8 gate_bit,
+		spinlock_t *lock);
+
+#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..59dee83
--- /dev/null
+++ b/drivers/clk/mediatek/clk-pll.c
@@ -0,0 +1,63 @@
+/*
+ * 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/io.h>
+#include <linux/slab.h>
+#include <linux/clkdev.h>
+
+#include "clk-mtk.h"
+#include "clk-pll.h"
+
+struct clk *mtk_clk_register_pll(
+		const char *name,
+		const char *parent_name,
+		u32 *base_addr,
+		u32 *pwr_addr,
+		u32 en_mask,
+		u32 flags,
+		const struct clk_ops *ops,
+		spinlock_t *lock)
+{
+	struct mtk_clk_pll *pll;
+	struct clk_init_data init;
+	struct clk *clk;
+
+	pr_debug("%s(): name: %s\n", __func__, name);
+
+	if (!lock)
+		return ERR_PTR(-EINVAL);
+
+	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+	if (!pll)
+		return ERR_PTR(-ENOMEM);
+
+	pll->base_addr = base_addr;
+	pll->pwr_addr = pwr_addr;
+	pll->en_mask = en_mask;
+	pll->flags = flags;
+	pll->lock = lock;
+	pll->hw.init = &init;
+
+	init.name = name;
+	init.ops = ops;
+	init.parent_names = &parent_name;
+	init.num_parents = 1;
+
+	clk = clk_register(NULL, &pll->hw);
+
+	if (IS_ERR(clk))
+		kfree(pll);
+
+	return clk;
+}
diff --git a/drivers/clk/mediatek/clk-pll.h b/drivers/clk/mediatek/clk-pll.h
new file mode 100644
index 0000000..341d2fe
--- /dev/null
+++ b/drivers/clk/mediatek/clk-pll.h
@@ -0,0 +1,52 @@
+/*
+ * 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_PLL_H
+#define __DRV_CLK_PLL_H
+
+/*
+ * This is a private header file. DO NOT include it except clk-*.c.
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+
+struct mtk_clk_pll {
+	struct clk_hw	hw;
+	void __iomem	*base_addr;
+	void __iomem	*pwr_addr;
+	u32		en_mask;
+	u32		flags;
+	spinlock_t	*lock;
+};
+
+#define to_mtk_clk_pll(_hw) container_of(_hw, struct mtk_clk_pll, hw)
+
+#define HAVE_RST_BAR	BIT(0)
+#define HAVE_PLL_HP	BIT(1)
+#define HAVE_FIX_FRQ	BIT(2)
+#define PLL_AO		BIT(3)
+
+struct clk *mtk_clk_register_pll(
+		const char *name,
+		const char *parent_name,
+		u32 *base_addr,
+		u32 *pwr_addr,
+		u32 en_mask,
+		u32 flags,
+		const struct clk_ops *ops,
+		spinlock_t *lock);
+
+#endif /* __DRV_CLK_PLL_H */
-- 
2.1.4


^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH 03/13] clk: mediatek: Add reset controller support
  2015-02-09 10:47 [PATCH v5]: clk: Add common clock support for Mediatek MT8135 and MT8173 Sascha Hauer
  2015-02-09 10:47 ` [PATCH 01/13] clk: dts: mediatek: add Mediatek MT8135 clock bindings Sascha Hauer
  2015-02-09 10:47 ` [PATCH 02/13] clk: mediatek: Add initial common clock support for Mediatek SoCs Sascha Hauer
@ 2015-02-09 10:47 ` Sascha Hauer
  2015-02-09 13:35   ` Philipp Zabel
  2015-02-09 10:47 ` [PATCH 04/13] clk: mediatek: Add basic clocks for Mediatek MT8135 Sascha Hauer
                   ` (9 subsequent siblings)
  12 siblings, 1 reply; 27+ messages in thread
From: Sascha Hauer @ 2015-02-09 10:47 UTC (permalink / raw)
  To: Matthias Brugger
  Cc: linux-arm-kernel, linux-kernel, Rob Herring, Eddie Huang,
	Lee Jones, Yingjoe Chen (陳英洲),
	Henry Chen, YH Chen (陳昱豪),
	kernel, Mike Turquette, Sascha Hauer

The pericfg and infracfg units also provide reset lines to several
other SoC internal units. Add support for the reset controller.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/clk/mediatek/Makefile  |  1 +
 drivers/clk/mediatek/clk-mtk.h | 10 +++++
 drivers/clk/mediatek/reset.c   | 99 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 110 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 35cf9a3..624863f 100644
--- a/drivers/clk/mediatek/clk-mtk.h
+++ b/drivers/clk/mediatek/clk-mtk.h
@@ -130,4 +130,14 @@ struct clk *mtk_clk_register_mux(
 		u8 gate_bit,
 		spinlock_t *lock);
 
+#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..3a85a53
--- /dev/null
+++ b/drivers/clk/mediatek/reset.c
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#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;
+	}
+}
-- 
2.1.4


^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH 04/13] clk: mediatek: Add basic clocks for Mediatek MT8135.
  2015-02-09 10:47 [PATCH v5]: clk: Add common clock support for Mediatek MT8135 and MT8173 Sascha Hauer
                   ` (2 preceding siblings ...)
  2015-02-09 10:47 ` [PATCH 03/13] clk: mediatek: Add reset controller support Sascha Hauer
@ 2015-02-09 10:47 ` Sascha Hauer
  2015-02-09 10:47 ` [PATCH 05/13] clk: dts: mediatek: add Mediatek MT8173 clock bindings Sascha Hauer
                   ` (8 subsequent siblings)
  12 siblings, 0 replies; 27+ messages in thread
From: Sascha Hauer @ 2015-02-09 10:47 UTC (permalink / raw)
  To: Matthias Brugger
  Cc: linux-arm-kernel, linux-kernel, Rob Herring, Eddie Huang,
	Lee Jones, Yingjoe Chen (陳英洲),
	Henry Chen, YH Chen (陳昱豪),
	kernel, Mike Turquette, James Liao, Sascha Hauer

From: James Liao <jamesjj.liao@mediatek.com>

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-pll.c | 860 +++++++++++++++++++++++++++++++++
 drivers/clk/mediatek/clk-mt8135-pll.h |  28 ++
 drivers/clk/mediatek/clk-mt8135.c     | 873 ++++++++++++++++++++++++++++++++++
 4 files changed, 1762 insertions(+)
 create mode 100644 drivers/clk/mediatek/clk-mt8135-pll.c
 create mode 100644 drivers/clk/mediatek/clk-mt8135-pll.h
 create mode 100644 drivers/clk/mediatek/clk-mt8135.c

diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile
index 0b6f1c3..afb52e5 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 clk-mt8135-pll.o
diff --git a/drivers/clk/mediatek/clk-mt8135-pll.c b/drivers/clk/mediatek/clk-mt8135-pll.c
new file mode 100644
index 0000000..81f5a00
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mt8135-pll.c
@@ -0,0 +1,860 @@
+/*
+ * 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/io.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/clkdev.h>
+
+#include "clk-mtk.h"
+#include "clk-pll.h"
+#include "clk-mt8135-pll.h"
+
+#define PLL_BASE_EN	BIT(0)
+#define PLL_PWR_ON	BIT(0)
+#define PLL_ISO_EN	BIT(1)
+#define PLL_PCW_CHG	BIT(31)
+#define RST_BAR_MASK	BIT(27)
+#define AUDPLL_TUNER_EN	BIT(31)
+
+#define PLL_PREDIV_H		5
+#define PLL_PREDIV_L		4
+#define PLL_PREDIV_MASK		GENMASK(PLL_PREDIV_H, PLL_PREDIV_L)
+#define PLL_VCODIV_L		19
+#define PLL_VCODIV_MASK		BIT(19)
+
+static const u32 pll_vcodivsel_map[2] = { 1, 2 };
+static const u32 pll_prediv_map[4] = { 1, 2, 4, 4 };
+static const u32 pll_posdiv_map[8] = { 1, 2, 4, 8, 16, 16, 16, 16 };
+static const u32 pll_fbksel_map[4] = { 1, 2, 4, 4 };
+
+static u32 mtk_calc_pll_vco_freq(
+		u32 fin,
+		u32 pcw,
+		u32 vcodivsel,
+		u32 prediv,
+		u32 pcwfbits)
+{
+	/* vco = (fin * pcw * vcodivsel / prediv) >> pcwfbits; */
+	u64 vco = fin;
+	u8 c = 0;
+
+	vco = vco * pcw * vcodivsel;
+	do_div(vco, prediv);
+
+	if (vco & GENMASK(pcwfbits - 1, 0))
+		c = 1;
+
+	vco >>= pcwfbits;
+
+	if (c)
+		++vco;
+
+	return (u32)vco;
+}
+
+static u32 mtk_freq_limit(u32 freq)
+{
+	static const u32 freq_max = 2000 * 1000 * 1000;		/* 2000 MHz */
+	static const u32 freq_min = 1000 * 1000 * 1000 / 16;	/* 62.5 MHz */
+
+	if (freq <= freq_min)
+		freq = freq_min + 16;
+	else if (freq > freq_max)
+		freq = freq_max;
+
+	return freq;
+}
+
+static int mtk_calc_pll_freq_cfg(
+		u32 *pcw,
+		u32 *postdiv_idx,
+		u32 freq,
+		u32 fin,
+		int pcwfbits)
+{
+	static const u64 freq_max = 2000 * 1000 * 1000;	/* 2000 MHz */
+	static const u64 freq_min = 1000 * 1000 * 1000;	/* 1000 MHz */
+	static const u64 postdiv[] = { 1, 2, 4, 8, 16 };
+	u64 n_info;
+	u32 idx;
+
+	/* search suitable postdiv */
+	for (idx = 0;
+		idx < ARRAY_SIZE(postdiv) && postdiv[idx] * freq <= freq_min;
+		idx++)
+		;
+
+	if (idx >= ARRAY_SIZE(postdiv))
+		return -EINVAL;	/* freq is out of range (too low) */
+	else if (postdiv[idx] * freq > freq_max)
+		return -EINVAL;	/* freq is out of range (too high) */
+
+	/* n_info = freq * postdiv / 26MHz * 2^pcwfbits */
+	n_info = (postdiv[idx] * freq) << pcwfbits;
+	do_div(n_info, fin);
+
+	*postdiv_idx = idx;
+	*pcw = (u32)n_info;
+
+	return 0;
+}
+
+static int mtk_clk_pll_is_enabled(struct clk_hw *hw)
+{
+	struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
+
+	return (readl_relaxed(pll->base_addr) & PLL_BASE_EN) != 0;
+}
+
+static int mtk_clk_pll_prepare(struct clk_hw *hw)
+{
+	unsigned long flags = 0;
+	struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
+	u32 r;
+
+	spin_lock_irqsave(pll->lock, flags);
+
+	r = readl_relaxed(pll->pwr_addr) | PLL_PWR_ON;
+	writel_relaxed(r, pll->pwr_addr);
+	wmb();	/* sync write before delay */
+	udelay(1);
+
+	r = readl_relaxed(pll->pwr_addr) & ~PLL_ISO_EN;
+	writel_relaxed(r, pll->pwr_addr);
+	wmb();	/* sync write before delay */
+	udelay(1);
+
+	r = readl_relaxed(pll->base_addr) | pll->en_mask;
+	writel_relaxed(r, pll->base_addr);
+	wmb();	/* sync write before delay */
+	udelay(20);
+
+	if (pll->flags & HAVE_RST_BAR) {
+		r = readl_relaxed(pll->base_addr) | RST_BAR_MASK;
+		writel_relaxed(r, pll->base_addr);
+	}
+
+	spin_unlock_irqrestore(pll->lock, flags);
+
+	return 0;
+}
+
+static void mtk_clk_pll_unprepare(struct clk_hw *hw)
+{
+	unsigned long flags = 0;
+	struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
+	u32 r;
+
+	if (pll->flags & PLL_AO)
+		return;
+
+	spin_lock_irqsave(pll->lock, flags);
+
+	if (pll->flags & HAVE_RST_BAR) {
+		r = readl_relaxed(pll->base_addr) & ~RST_BAR_MASK;
+		writel_relaxed(r, pll->base_addr);
+	}
+
+	r = readl_relaxed(pll->base_addr) & ~PLL_BASE_EN;
+	writel_relaxed(r, pll->base_addr);
+
+	r = readl_relaxed(pll->pwr_addr) | PLL_ISO_EN;
+	writel_relaxed(r, pll->pwr_addr);
+
+	r = readl_relaxed(pll->pwr_addr) & ~PLL_PWR_ON;
+	writel_relaxed(r, pll->pwr_addr);
+
+	spin_unlock_irqrestore(pll->lock, flags);
+}
+
+static long mtk_clk_pll_round_rate(
+		struct clk_hw *hw,
+		unsigned long rate,
+		unsigned long *prate)
+{
+	u32 pcwfbits = 14;
+	u32 pcw = 0;
+	u32 postdiv = 0;
+	u32 r;
+
+	*prate = *prate ? *prate : 26000000;
+	rate = mtk_freq_limit(rate);
+	mtk_calc_pll_freq_cfg(&pcw, &postdiv, rate, *prate, pcwfbits);
+
+	r = mtk_calc_pll_vco_freq(*prate, pcw, 1, 1, pcwfbits);
+	r = (r + pll_posdiv_map[postdiv] - 1) / pll_posdiv_map[postdiv];
+
+	return r;
+}
+
+#define SDM_PLL_POSTDIV_H	8
+#define SDM_PLL_POSTDIV_L	6
+#define SDM_PLL_POSTDIV_MASK	GENMASK(SDM_PLL_POSTDIV_H, SDM_PLL_POSTDIV_L)
+#define SDM_PLL_PCW_H		20
+#define SDM_PLL_PCW_L		0
+#define SDM_PLL_PCW_MASK	GENMASK(SDM_PLL_PCW_H, SDM_PLL_PCW_L)
+
+static unsigned long mtk_clk_pll_recalc_rate(
+		struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
+
+	u32 con0 = readl_relaxed(pll->base_addr);
+	u32 con1 = readl_relaxed(pll->base_addr + 4);
+
+	u32 vcodivsel = (con0 & PLL_VCODIV_MASK) >> PLL_VCODIV_L;
+	u32 prediv = (con0 & PLL_PREDIV_MASK) >> PLL_PREDIV_L;
+	u32 posdiv = (con0 & SDM_PLL_POSTDIV_MASK) >> SDM_PLL_POSTDIV_L;
+	u32 pcw = (con1 & SDM_PLL_PCW_MASK) >> SDM_PLL_PCW_L;
+	u32 pcwfbits = 14;
+
+	u32 vco_freq;
+	unsigned long r;
+
+	parent_rate = parent_rate ? parent_rate : 26000000;
+	vcodivsel = pll_vcodivsel_map[vcodivsel];
+	prediv = pll_prediv_map[prediv];
+
+	vco_freq = mtk_calc_pll_vco_freq(
+			parent_rate, pcw, vcodivsel, prediv, pcwfbits);
+	r = (vco_freq + pll_posdiv_map[posdiv] - 1) / pll_posdiv_map[posdiv];
+
+	return r;
+}
+
+static void mtk_clk_pll_set_rate_regs(
+		struct clk_hw *hw,
+		u32 pcw,
+		u32 postdiv_idx)
+{
+	unsigned long flags = 0;
+	struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
+	void __iomem *con0_addr = pll->base_addr;
+	void __iomem *con1_addr = pll->base_addr + 4;
+	u32 con0;
+	u32 con1;
+	u32 pll_en;
+
+	spin_lock_irqsave(pll->lock, flags);
+
+	con0 = readl_relaxed(con0_addr);
+	con1 = readl_relaxed(con1_addr);
+
+	pll_en = con0 & PLL_BASE_EN;
+
+	/* set postdiv */
+	con0 &= ~SDM_PLL_POSTDIV_MASK;
+	con0 |= postdiv_idx << SDM_PLL_POSTDIV_L;
+	writel_relaxed(con0, con0_addr);
+
+	/* set pcw */
+	con1 &= ~SDM_PLL_PCW_MASK;
+	con1 |= pcw << SDM_PLL_PCW_L;
+
+	if (pll_en)
+		con1 |= PLL_PCW_CHG;
+
+	writel_relaxed(con1, con1_addr);
+
+	if (pll_en) {
+		wmb();	/* sync write before delay */
+		udelay(20);
+	}
+
+	spin_unlock_irqrestore(pll->lock, flags);
+}
+
+static int mtk_clk_pll_set_rate(
+		struct clk_hw *hw,
+		unsigned long rate,
+		unsigned long parent_rate)
+{
+	u32 pcwfbits = 14;
+	u32 pcw = 0;
+	u32 postdiv_idx = 0;
+	int r;
+
+	parent_rate = parent_rate ? parent_rate : 26000000;
+	r = mtk_calc_pll_freq_cfg(&pcw, &postdiv_idx, rate,
+			parent_rate, pcwfbits);
+
+	if (r == 0)
+		mtk_clk_pll_set_rate_regs(hw, pcw, postdiv_idx);
+
+	return r;
+}
+
+const struct clk_ops mt8135_pll_ops = {
+	.is_enabled	= mtk_clk_pll_is_enabled,
+	.prepare	= mtk_clk_pll_prepare,
+	.unprepare	= mtk_clk_pll_unprepare,
+	.recalc_rate	= mtk_clk_pll_recalc_rate,
+	.round_rate	= mtk_clk_pll_round_rate,
+	.set_rate	= mtk_clk_pll_set_rate,
+};
+
+#define ARM_PLL_POSTDIV_H	26
+#define ARM_PLL_POSTDIV_L	24
+#define ARM_PLL_POSTDIV_MASK	GENMASK(ARM_PLL_POSTDIV_H, ARM_PLL_POSTDIV_L)
+#define ARM_PLL_PCW_H		20
+#define ARM_PLL_PCW_L		0
+#define ARM_PLL_PCW_MASK	GENMASK(ARM_PLL_PCW_H, ARM_PLL_PCW_L)
+
+static unsigned long mtk_clk_arm_pll_recalc_rate(
+		struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
+
+	u32 con0 = readl_relaxed(pll->base_addr);
+	u32 con1 = readl_relaxed(pll->base_addr + 4);
+
+	u32 vcodivsel = (con0 & PLL_VCODIV_MASK) >> PLL_VCODIV_L;
+	u32 prediv = (con0 & PLL_PREDIV_MASK) >> PLL_PREDIV_L;
+	u32 posdiv = (con1 & ARM_PLL_POSTDIV_MASK) >> ARM_PLL_POSTDIV_L;
+	u32 pcw = (con1 & ARM_PLL_PCW_MASK) >> ARM_PLL_PCW_L;
+	u32 pcwfbits = 14;
+
+	u32 vco_freq;
+	unsigned long r;
+
+	parent_rate = parent_rate ? parent_rate : 26000000;
+	vcodivsel = pll_vcodivsel_map[vcodivsel];
+	prediv = pll_prediv_map[prediv];
+
+	vco_freq = mtk_calc_pll_vco_freq(
+			parent_rate, pcw, vcodivsel, prediv, pcwfbits);
+	r = (vco_freq + pll_posdiv_map[posdiv] - 1) / pll_posdiv_map[posdiv];
+
+	return r;
+}
+
+static void mtk_clk_arm_pll_set_rate_regs(
+		struct clk_hw *hw,
+		u32 pcw,
+		u32 postdiv_idx)
+
+{
+	unsigned long flags = 0;
+	struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
+	void __iomem *con0_addr = pll->base_addr;
+	void __iomem *con1_addr = pll->base_addr + 4;
+	u32 con0;
+	u32 con1;
+	u32 pll_en;
+
+	spin_lock_irqsave(pll->lock, flags);
+
+	con0 = readl_relaxed(con0_addr);
+	con1 = readl_relaxed(con1_addr);
+
+	pll_en = con0 & PLL_BASE_EN;
+
+	/* postdiv */
+	con1 &= ~ARM_PLL_POSTDIV_MASK;
+	con1 |= postdiv_idx << ARM_PLL_POSTDIV_L;
+
+	/* pcw */
+	con1 &= ~ARM_PLL_PCW_MASK;
+	con1 |= pcw << ARM_PLL_PCW_L;
+
+	if (pll_en)
+		con1 |= PLL_PCW_CHG;
+
+	writel_relaxed(con1, con1_addr);
+
+	if (pll_en) {
+		wmb();	/* sync write before delay */
+		udelay(20);
+	}
+
+	spin_unlock_irqrestore(pll->lock, flags);
+}
+
+static int mtk_clk_arm_pll_set_rate(
+		struct clk_hw *hw,
+		unsigned long rate,
+		unsigned long parent_rate)
+{
+	u32 pcwfbits = 14;
+	u32 pcw = 0;
+	u32 postdiv_idx = 0;
+	int r;
+
+	parent_rate = parent_rate ? parent_rate : 26000000;
+	r = mtk_calc_pll_freq_cfg(&pcw, &postdiv_idx, rate,
+			parent_rate, pcwfbits);
+
+	if (r == 0)
+		mtk_clk_arm_pll_set_rate_regs(hw, pcw, postdiv_idx);
+
+	return r;
+}
+
+const struct clk_ops mt8135_arm_pll_ops = {
+	.is_enabled	= mtk_clk_pll_is_enabled,
+	.prepare	= mtk_clk_pll_prepare,
+	.unprepare	= mtk_clk_pll_unprepare,
+	.recalc_rate	= mtk_clk_arm_pll_recalc_rate,
+	.round_rate	= mtk_clk_pll_round_rate,
+	.set_rate	= mtk_clk_arm_pll_set_rate,
+};
+
+static int mtk_clk_lc_pll_prepare(struct clk_hw *hw)
+{
+	unsigned long flags = 0;
+	struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
+	u32 r;
+
+	spin_lock_irqsave(pll->lock, flags);
+
+	r = readl_relaxed(pll->base_addr) | pll->en_mask;
+	writel_relaxed(r, pll->base_addr);
+	wmb();	/* sync write before delay */
+	udelay(20);
+
+	if (pll->flags & HAVE_RST_BAR) {
+		r = readl_relaxed(pll->base_addr) | RST_BAR_MASK;
+		writel_relaxed(r, pll->base_addr);
+	}
+
+	spin_unlock_irqrestore(pll->lock, flags);
+
+	return 0;
+}
+
+static void mtk_clk_lc_pll_unprepare(struct clk_hw *hw)
+{
+	unsigned long flags = 0;
+	struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
+	u32 r;
+
+	if (pll->flags & PLL_AO)
+		return;
+
+	spin_lock_irqsave(pll->lock, flags);
+
+	if (pll->flags & HAVE_RST_BAR) {
+		r = readl_relaxed(pll->base_addr) & ~RST_BAR_MASK;
+		writel_relaxed(r, pll->base_addr);
+	}
+
+	r = readl_relaxed(pll->base_addr) & ~PLL_BASE_EN;
+	writel_relaxed(r, pll->base_addr);
+
+	spin_unlock_irqrestore(pll->lock, flags);
+}
+
+#define LC_PLL_FBKSEL_H		21
+#define LC_PLL_FBKSEL_L		20
+#define LC_PLL_FBKSEL_MASK	GENMASK(LC_PLL_FBKSEL_H, LC_PLL_FBKSEL_L)
+#define LC_PLL_POSTDIV_H	8
+#define LC_PLL_POSTDIV_L	6
+#define LC_PLL_POSTDIV_MASK	GENMASK(LC_PLL_POSTDIV_H, LC_PLL_POSTDIV_L)
+#define LC_PLL_FBKDIV_H		15
+#define LC_PLL_FBKDIV_L		9
+#define LC_PLL_FBKDIV_MASK	GENMASK(LC_PLL_FBKDIV_H, LC_PLL_FBKDIV_L)
+
+static unsigned long mtk_clk_lc_pll_recalc_rate(
+		struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
+
+	u32 con0 = readl_relaxed(pll->base_addr);
+
+	u32 fbksel = (con0 & LC_PLL_FBKSEL_MASK) >> LC_PLL_FBKSEL_L;
+	u32 vcodivsel = (con0 & PLL_VCODIV_MASK) >> PLL_VCODIV_L;
+	u32 fbkdiv = (con0 & LC_PLL_FBKDIV_MASK) >> LC_PLL_FBKDIV_L;
+	u32 prediv = (con0 & PLL_PREDIV_MASK) >> PLL_PREDIV_L;
+	u32 posdiv = (con0 & LC_PLL_POSTDIV_MASK) >> LC_PLL_POSTDIV_L;
+
+	u32 vco_freq;
+	unsigned long r;
+
+	parent_rate = parent_rate ? parent_rate : 26000000;
+	vcodivsel = pll_vcodivsel_map[vcodivsel];
+	fbksel = pll_fbksel_map[fbksel];
+	prediv = pll_prediv_map[prediv];
+
+	vco_freq = parent_rate * fbkdiv * fbksel * vcodivsel / prediv;
+	r = (vco_freq + pll_posdiv_map[posdiv] - 1) / pll_posdiv_map[posdiv];
+
+	return r;
+}
+
+static void mtk_clk_lc_pll_set_rate_regs(
+		struct clk_hw *hw,
+		u32 pcw,
+		u32 postdiv_idx)
+{
+	unsigned long flags = 0;
+	struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
+	void __iomem *con0_addr = pll->base_addr;
+	u32 con0;
+	u32 pll_en;
+
+	spin_lock_irqsave(pll->lock, flags);
+
+	con0 = readl_relaxed(con0_addr);
+
+	pll_en = con0 & PLL_BASE_EN;
+
+	/* postdiv */
+	con0 &= ~LC_PLL_POSTDIV_MASK;
+	con0 |= postdiv_idx << LC_PLL_POSTDIV_L;
+
+	/* fkbdiv */
+	con0 &= ~LC_PLL_FBKDIV_MASK;
+	con0 |= pcw << LC_PLL_FBKDIV_L;
+
+	writel_relaxed(con0, con0_addr);
+
+	if (pll_en) {
+		wmb();	/* sync write before delay */
+		udelay(20);
+	}
+
+	spin_unlock_irqrestore(pll->lock, flags);
+}
+
+static long mtk_clk_lc_pll_round_rate(
+		struct clk_hw *hw,
+		unsigned long rate,
+		unsigned long *prate)
+{
+	u32 pcwfbits = 0;
+	u32 pcw = 0;
+	u32 postdiv = 0;
+	u32 r;
+
+	*prate = *prate ? *prate : 26000000;
+	rate = mtk_freq_limit(rate);
+	mtk_calc_pll_freq_cfg(&pcw, &postdiv, rate, *prate, pcwfbits);
+
+	r = mtk_calc_pll_vco_freq(*prate, pcw, 1, 1, pcwfbits);
+	r = (r + pll_posdiv_map[postdiv] - 1) / pll_posdiv_map[postdiv];
+
+	return r;
+}
+
+static int mtk_clk_lc_pll_set_rate(
+		struct clk_hw *hw,
+		unsigned long rate,
+		unsigned long parent_rate)
+{
+	u32 pcwfbits = 0;
+	u32 pcw = 0;
+	u32 postdiv_idx = 0;
+	int r;
+
+	parent_rate = parent_rate ? parent_rate : 26000000;
+	r = mtk_calc_pll_freq_cfg(&pcw, &postdiv_idx, rate,
+			parent_rate, pcwfbits);
+
+	if (r == 0)
+		mtk_clk_lc_pll_set_rate_regs(hw, pcw, postdiv_idx);
+
+	return r;
+}
+
+const struct clk_ops mt8135_lc_pll_ops = {
+	.is_enabled	= mtk_clk_pll_is_enabled,
+	.prepare	= mtk_clk_lc_pll_prepare,
+	.unprepare	= mtk_clk_lc_pll_unprepare,
+	.recalc_rate	= mtk_clk_lc_pll_recalc_rate,
+	.round_rate	= mtk_clk_lc_pll_round_rate,
+	.set_rate	= mtk_clk_lc_pll_set_rate,
+};
+
+static int mtk_clk_aud_pll_prepare(struct clk_hw *hw)
+{
+	unsigned long flags = 0;
+	struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
+	void __iomem *con0_addr = pll->base_addr;
+	void __iomem *con4_addr = pll->base_addr + 16;
+	u32 r;
+
+	spin_lock_irqsave(pll->lock, flags);
+
+	r = readl_relaxed(pll->pwr_addr) | PLL_PWR_ON;
+	writel_relaxed(r, pll->pwr_addr);
+	wmb();	/* sync write before delay */
+	udelay(1);
+
+	r = readl_relaxed(pll->pwr_addr) & ~PLL_ISO_EN;
+	writel_relaxed(r, pll->pwr_addr);
+	wmb();	/* sync write before delay */
+	udelay(1);
+
+	r = readl_relaxed(con0_addr) | pll->en_mask;
+	writel_relaxed(r, con0_addr);
+
+	r = readl_relaxed(con4_addr) | AUDPLL_TUNER_EN;
+	writel_relaxed(r, con4_addr);
+	wmb();	/* sync write before delay */
+	udelay(20);
+
+	if (pll->flags & HAVE_RST_BAR) {
+		r = readl_relaxed(con0_addr) | RST_BAR_MASK;
+		writel_relaxed(r, con0_addr);
+	}
+
+	spin_unlock_irqrestore(pll->lock, flags);
+
+	return 0;
+}
+
+static void mtk_clk_aud_pll_unprepare(struct clk_hw *hw)
+{
+	unsigned long flags = 0;
+	struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
+	void __iomem *con0_addr = pll->base_addr;
+	void __iomem *con4_addr = pll->base_addr + 16;
+	u32 r;
+
+	if (pll->flags & PLL_AO)
+		return;
+
+	spin_lock_irqsave(pll->lock, flags);
+
+	if (pll->flags & HAVE_RST_BAR) {
+		r = readl_relaxed(con0_addr) & ~RST_BAR_MASK;
+		writel_relaxed(r, con0_addr);
+	}
+
+	r = readl_relaxed(con4_addr) & ~AUDPLL_TUNER_EN;
+	writel_relaxed(r, con4_addr);
+
+	r = readl_relaxed(con0_addr) & ~PLL_BASE_EN;
+	writel_relaxed(r, con0_addr);
+
+	r = readl_relaxed(pll->pwr_addr) | PLL_ISO_EN;
+	writel_relaxed(r, pll->pwr_addr);
+
+	r = readl_relaxed(pll->pwr_addr) & ~PLL_PWR_ON;
+	writel_relaxed(r, pll->pwr_addr);
+
+	spin_unlock_irqrestore(pll->lock, flags);
+}
+
+#define AUD_PLL_POSTDIV_H	8
+#define AUD_PLL_POSTDIV_L	6
+#define AUD_PLL_POSTDIV_MASK	GENMASK(AUD_PLL_POSTDIV_H, AUD_PLL_POSTDIV_L)
+#define AUD_PLL_PCW_H		30
+#define AUD_PLL_PCW_L		0
+#define AUD_PLL_PCW_MASK	GENMASK(AUD_PLL_PCW_H, AUD_PLL_PCW_L)
+
+static unsigned long mtk_clk_aud_pll_recalc_rate(
+		struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
+
+	u32 con0 = readl_relaxed(pll->base_addr);
+	u32 con1 = readl_relaxed(pll->base_addr + 4);
+
+	u32 vcodivsel = (con0 & PLL_VCODIV_MASK) >> PLL_VCODIV_L;
+	u32 prediv = (con0 & PLL_PREDIV_MASK) >> PLL_PREDIV_L;
+	u32 posdiv = (con0 & AUD_PLL_POSTDIV_MASK) >> AUD_PLL_POSTDIV_L;
+	u32 pcw = (con1 & AUD_PLL_PCW_MASK) >> AUD_PLL_PCW_L;
+	u32 pcwfbits = 24;
+
+	u32 vco_freq;
+	unsigned long r;
+
+	parent_rate = parent_rate ? parent_rate : 26000000;
+	vcodivsel = pll_vcodivsel_map[vcodivsel];
+	prediv = pll_prediv_map[prediv];
+
+	vco_freq = mtk_calc_pll_vco_freq(
+			parent_rate, pcw, vcodivsel, prediv, pcwfbits);
+	r = (vco_freq + pll_posdiv_map[posdiv] - 1) / pll_posdiv_map[posdiv];
+
+	return r;
+}
+
+static void mtk_clk_aud_pll_set_rate_regs(
+		struct clk_hw *hw,
+		u32 pcw,
+		u32 postdiv_idx)
+{
+	unsigned long flags = 0;
+	struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
+	void __iomem *con0_addr = pll->base_addr;
+	void __iomem *con1_addr = pll->base_addr + 4;
+	void __iomem *con4_addr = pll->base_addr + 16;
+	u32 con0;
+	u32 con1;
+	u32 pll_en;
+
+	spin_lock_irqsave(pll->lock, flags);
+
+	con0 = readl_relaxed(con0_addr);
+	con1 = readl_relaxed(con1_addr);
+
+	pll_en = con0 & PLL_BASE_EN;
+
+	/* set postdiv */
+	con0 &= ~AUD_PLL_POSTDIV_MASK;
+	con0 |= postdiv_idx << AUD_PLL_POSTDIV_L;
+	writel_relaxed(con0, con0_addr);
+
+	/* set pcw */
+	con1 &= ~AUD_PLL_PCW_MASK;
+	con1 |= pcw << AUD_PLL_PCW_L;
+
+	if (pll_en)
+		con1 |= PLL_PCW_CHG;
+
+	writel_relaxed(con1, con1_addr);
+	writel_relaxed(con1 + 1, con4_addr);
+	/* AUDPLL_CON4[30:0] (AUDPLL_TUNER_N_INFO) = (pcw + 1) */
+
+	if (pll_en) {
+		wmb();	/* sync write before delay */
+		udelay(20);
+	}
+
+	spin_unlock_irqrestore(pll->lock, flags);
+}
+
+static long mtk_clk_aud_pll_round_rate(
+		struct clk_hw *hw,
+		unsigned long rate,
+		unsigned long *prate)
+{
+	u32 pcwfbits = 24;
+	u32 pcw = 0;
+	u32 postdiv = 0;
+	u32 r;
+
+	*prate = *prate ? *prate : 26000000;
+	rate = mtk_freq_limit(rate);
+	mtk_calc_pll_freq_cfg(&pcw, &postdiv, rate, *prate, pcwfbits);
+
+	r = mtk_calc_pll_vco_freq(*prate, pcw, 1, 1, pcwfbits);
+	r = (r + pll_posdiv_map[postdiv] - 1) / pll_posdiv_map[postdiv];
+
+	return r;
+}
+
+static int mtk_clk_aud_pll_set_rate(
+		struct clk_hw *hw,
+		unsigned long rate,
+		unsigned long parent_rate)
+{
+	u32 pcwfbits = 24;
+	u32 pcw = 0;
+	u32 postdiv_idx = 0;
+	int r;
+
+	parent_rate = parent_rate ? parent_rate : 26000000;
+	r = mtk_calc_pll_freq_cfg(&pcw, &postdiv_idx, rate,
+			parent_rate, pcwfbits);
+
+	if (r == 0)
+		mtk_clk_aud_pll_set_rate_regs(hw, pcw, postdiv_idx);
+
+	return r;
+}
+
+const struct clk_ops mt8135_aud_pll_ops = {
+	.is_enabled	= mtk_clk_pll_is_enabled,
+	.prepare	= mtk_clk_aud_pll_prepare,
+	.unprepare	= mtk_clk_aud_pll_unprepare,
+	.recalc_rate	= mtk_clk_aud_pll_recalc_rate,
+	.round_rate	= mtk_clk_aud_pll_round_rate,
+	.set_rate	= mtk_clk_aud_pll_set_rate,
+};
+
+#define TVD_PLL_POSTDIV_H	8
+#define TVD_PLL_POSTDIV_L	6
+#define TVD_PLL_POSTDIV_MASK	GENMASK(TVD_PLL_POSTDIV_H, TVD_PLL_POSTDIV_L)
+#define TVD_PLL_PCW_H		30
+#define TVD_PLL_PCW_L		0
+#define TVD_PLL_PCW_MASK	GENMASK(TVD_PLL_PCW_H, TVD_PLL_PCW_L)
+
+static void mtk_clk_tvd_pll_set_rate_regs(
+		struct clk_hw *hw,
+		u32 pcw,
+		u32 postdiv_idx)
+{
+	unsigned long flags = 0;
+	struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
+	void __iomem *con0_addr = pll->base_addr;
+	void __iomem *con1_addr = pll->base_addr + 4;
+	u32 con0;
+	u32 con1;
+	u32 pll_en;
+
+	spin_lock_irqsave(pll->lock, flags);
+
+	con0 = readl_relaxed(con0_addr);
+	con1 = readl_relaxed(con1_addr);
+
+	pll_en = con0 & PLL_BASE_EN;
+
+	/* set postdiv */
+	con0 &= ~TVD_PLL_POSTDIV_MASK;
+	con0 |= postdiv_idx << TVD_PLL_POSTDIV_L;
+	writel_relaxed(con0, con0_addr);
+
+	/* set pcw */
+	con1 &= ~TVD_PLL_PCW_MASK;
+	con1 |= pcw << TVD_PLL_PCW_L;
+
+	if (pll_en)
+		con1 |= PLL_PCW_CHG;
+
+	writel_relaxed(con1, con1_addr);
+
+	if (pll_en) {
+		wmb();	/* sync write before delay */
+		udelay(20);
+	}
+
+	spin_unlock_irqrestore(pll->lock, flags);
+}
+
+static int mtk_clk_tvd_pll_set_rate(
+		struct clk_hw *hw,
+		unsigned long rate,
+		unsigned long parent_rate)
+{
+	u32 pcwfbits = 24;
+	u32 pcw = 0;
+	u32 postdiv_idx = 0;
+	int r;
+
+	parent_rate = parent_rate ? parent_rate : 26000000;
+	r = mtk_calc_pll_freq_cfg(&pcw, &postdiv_idx, rate,
+			parent_rate, pcwfbits);
+
+	if (r == 0)
+		mtk_clk_tvd_pll_set_rate_regs(hw, pcw, postdiv_idx);
+
+	return r;
+}
+
+const struct clk_ops mt8135_tvd_pll_ops = {
+	.is_enabled	= mtk_clk_pll_is_enabled,
+	.prepare	= mtk_clk_pll_prepare,
+	.unprepare	= mtk_clk_pll_unprepare,
+	.recalc_rate	= mtk_clk_aud_pll_recalc_rate,
+	.round_rate	= mtk_clk_aud_pll_round_rate,
+	.set_rate	= mtk_clk_tvd_pll_set_rate,
+};
diff --git a/drivers/clk/mediatek/clk-mt8135-pll.h b/drivers/clk/mediatek/clk-mt8135-pll.h
new file mode 100644
index 0000000..dba18e08
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mt8135-pll.h
@@ -0,0 +1,28 @@
+/*
+ * 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_MT8135_PLL_H
+#define __DRV_CLK_MT8135_PLL_H
+
+/*
+ * This is a private header file. DO NOT include it except clk-*.c.
+ */
+
+extern const struct clk_ops mt8135_pll_ops;
+extern const struct clk_ops mt8135_arm_pll_ops;
+extern const struct clk_ops mt8135_lc_pll_ops;
+extern const struct clk_ops mt8135_aud_pll_ops;
+extern const struct clk_ops mt8135_tvd_pll_ops;
+
+#endif /* __DRV_CLK_MT8135_PLL_H */
diff --git a/drivers/clk/mediatek/clk-mt8135.c b/drivers/clk/mediatek/clk-mt8135.c
new file mode 100644
index 0000000..93e5f02
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mt8135.c
@@ -0,0 +1,873 @@
+/*
+ * 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-pll.h"
+#include "clk-gate.h"
+#include "clk-mt8135-pll.h"
+
+#include <dt-bindings/clock/mt8135-clk.h>
+
+/* ROOT */
+#define clk_null		"clk_null"
+#define clk26m			"clk26m"
+#define rtc32k			"rtc32k"
+
+#define dsi0_lntc_dsiclk	"dsi0_lntc_dsi"
+#define hdmitx_clkdig_cts	"hdmitx_dig_cts"
+#define clkph_mck		"clkph_mck"
+#define cpum_tck_in		"cpum_tck_in"
+
+/* PLL */
+#define armpll1			"armpll1"
+#define armpll2			"armpll2"
+#define mainpll			"mainpll"
+#define univpll			"univpll"
+#define mmpll			"mmpll"
+#define msdcpll			"msdcpll"
+#define tvdpll			"tvdpll"
+#define lvdspll			"lvdspll"
+#define audpll			"audpll"
+#define vdecpll			"vdecpll"
+
+#define mainpll_806m		"mainpll_806m"
+#define mainpll_537p3m		"mainpll_537p3m"
+#define mainpll_322p4m		"mainpll_322p4m"
+#define mainpll_230p3m		"mainpll_230p3m"
+
+#define univpll_624m		"univpll_624m"
+#define univpll_416m		"univpll_416m"
+#define univpll_249p6m		"univpll_249p6m"
+#define univpll_178p3m		"univpll_178p3m"
+#define univpll_48m		"univpll_48m"
+
+/* DIV */
+#define mmpll_d2		"mmpll_d2"
+#define mmpll_d3		"mmpll_d3"
+#define mmpll_d5		"mmpll_d5"
+#define mmpll_d7		"mmpll_d7"
+#define mmpll_d4		"mmpll_d4"
+#define mmpll_d6		"mmpll_d6"
+
+#define syspll_d2		"syspll_d2"
+#define syspll_d4		"syspll_d4"
+#define syspll_d6		"syspll_d6"
+#define syspll_d8		"syspll_d8"
+#define syspll_d10		"syspll_d10"
+#define syspll_d12		"syspll_d12"
+#define syspll_d16		"syspll_d16"
+#define syspll_d24		"syspll_d24"
+#define syspll_d3		"syspll_d3"
+#define syspll_d2p5		"syspll_d2p5"
+#define syspll_d5		"syspll_d5"
+#define syspll_d3p5		"syspll_d3p5"
+
+#define univpll1_d2		"univpll1_d2"
+#define univpll1_d4		"univpll1_d4"
+#define univpll1_d6		"univpll1_d6"
+#define univpll1_d8		"univpll1_d8"
+#define univpll1_d10		"univpll1_d10"
+
+#define univpll2_d2		"univpll2_d2"
+#define univpll2_d4		"univpll2_d4"
+#define univpll2_d6		"univpll2_d6"
+#define univpll2_d8		"univpll2_d8"
+
+#define univpll_d3		"univpll_d3"
+#define univpll_d5		"univpll_d5"
+#define univpll_d7		"univpll_d7"
+#define univpll_d10		"univpll_d10"
+#define univpll_d26		"univpll_d26"
+
+#define apll_ck			"apll"
+#define apll_d4			"apll_d4"
+#define apll_d8			"apll_d8"
+#define apll_d16		"apll_d16"
+#define apll_d24		"apll_d24"
+
+#define lvdspll_d2		"lvdspll_d2"
+#define lvdspll_d4		"lvdspll_d4"
+#define lvdspll_d8		"lvdspll_d8"
+
+#define lvdstx_clkdig_cts	"lvdstx_dig_cts"
+#define vpll_dpix_ck		"vpll_dpix_ck"
+#define tvhdmi_h_ck		"tvhdmi_h_ck"
+#define hdmitx_clkdig_d2	"hdmitx_dig_d2"
+#define hdmitx_clkdig_d3	"hdmitx_dig_d3"
+#define tvhdmi_d2		"tvhdmi_d2"
+#define tvhdmi_d4		"tvhdmi_d4"
+#define mempll_mck_d4		"mempll_mck_d4"
+
+/* TOP */
+#define axi_sel			"axi_sel"
+#define smi_sel			"smi_sel"
+#define mfg_sel			"mfg_sel"
+#define irda_sel		"irda_sel"
+#define cam_sel			"cam_sel"
+#define aud_intbus_sel		"aud_intbus_sel"
+#define jpg_sel			"jpg_sel"
+#define disp_sel		"disp_sel"
+#define msdc30_1_sel		"msdc30_1_sel"
+#define msdc30_2_sel		"msdc30_2_sel"
+#define msdc30_3_sel		"msdc30_3_sel"
+#define msdc30_4_sel		"msdc30_4_sel"
+#define usb20_sel		"usb20_sel"
+#define venc_sel		"venc_sel"
+#define spi_sel			"spi_sel"
+#define uart_sel		"uart_sel"
+#define mem_sel			"mem_sel"
+#define camtg_sel		"camtg_sel"
+#define audio_sel		"audio_sel"
+#define fix_sel			"fix_sel"
+#define vdec_sel		"vdec_sel"
+#define ddrphycfg_sel		"ddrphycfg_sel"
+#define dpilvds_sel		"dpilvds_sel"
+#define pmicspi_sel		"pmicspi_sel"
+#define msdc30_0_sel		"msdc30_0_sel"
+#define smi_mfg_as_sel		"smi_mfg_as_sel"
+#define gcpu_sel		"gcpu_sel"
+#define dpi1_sel		"dpi1_sel"
+#define cci_sel			"cci_sel"
+#define apll_sel		"apll_sel"
+#define hdmipll_sel		"hdmipll_sel"
+
+/* PERI0 */
+#define i2c5_ck			"i2c5_ck"
+#define i2c4_ck			"i2c4_ck"
+#define i2c3_ck			"i2c3_ck"
+#define i2c2_ck			"i2c2_ck"
+#define i2c1_ck			"i2c1_ck"
+#define i2c0_ck			"i2c0_ck"
+#define uart3_ck		"uart3_ck"
+#define uart2_ck		"uart2_ck"
+#define uart1_ck		"uart1_ck"
+#define uart0_ck		"uart0_ck"
+#define irda_ck			"irda_ck"
+#define nli_ck			"nli_ck"
+#define md_hif_ck		"md_hif_ck"
+#define ap_hif_ck		"ap_hif_ck"
+#define msdc30_3_ck		"msdc30_3_ck"
+#define msdc30_2_ck		"msdc30_2_ck"
+#define msdc30_1_ck		"msdc30_1_ck"
+#define msdc20_2_ck		"msdc20_2_ck"
+#define msdc20_1_ck		"msdc20_1_ck"
+#define ap_dma_ck		"ap_dma_ck"
+#define usb1_ck			"usb1_ck"
+#define usb0_ck			"usb0_ck"
+#define pwm_ck			"pwm_ck"
+#define pwm7_ck			"pwm7_ck"
+#define pwm6_ck			"pwm6_ck"
+#define pwm5_ck			"pwm5_ck"
+#define pwm4_ck			"pwm4_ck"
+#define pwm3_ck			"pwm3_ck"
+#define pwm2_ck			"pwm2_ck"
+#define pwm1_ck			"pwm1_ck"
+#define therm_ck		"therm_ck"
+#define nfi_ck			"nfi_ck"
+
+/* PERI1 */
+#define usbslv_ck		"usbslv_ck"
+#define usb1_mcu_ck		"usb1_mcu_ck"
+#define usb0_mcu_ck		"usb0_mcu_ck"
+#define gcpu_ck			"gcpu_ck"
+#define fhctl_ck		"fhctl_ck"
+#define spi1_ck			"spi1_ck"
+#define auxadc_ck		"auxadc_ck"
+#define peri_pwrap_ck		"peri_pwrap_ck"
+#define i2c6_ck			"i2c6_ck"
+
+/* INFRA */
+#define pmic_wrap_ck		"pmic_wrap_ck"
+#define pmicspi_ck		"pmicspi_ck"
+#define ccif1_ap_ctrl		"ccif1_ap_ctrl"
+#define ccif0_ap_ctrl		"ccif0_ap_ctrl"
+#define kp_ck			"kp_ck"
+#define cpum_ck			"cpum_ck"
+#define m4u_ck			"m4u_ck"
+#define mfgaxi_ck		"mfgaxi_ck"
+#define devapc_ck		"devapc_ck"
+#define audio_ck		"audio_ck"
+#define mfg_bus_ck		"mfg_bus_ck"
+#define smi_ck			"smi_ck"
+#define dbgclk_ck		"dbgclk_ck"
+
+static DEFINE_SPINLOCK(lock);
+
+static struct mtk_fixed_factor root_clk_alias[] __initdata = {
+	FACTOR(TOP_DSI0_LNTC_DSICLK, dsi0_lntc_dsiclk, clk_null, 1, 1),
+	FACTOR(TOP_HDMITX_CLKDIG_CTS, hdmitx_clkdig_cts, clk_null, 1, 1),
+	FACTOR(TOP_CLKPH_MCK, clkph_mck, clk_null, 1, 1),
+	FACTOR(TOP_CPUM_TCK_IN, cpum_tck_in, clk_null, 1, 1),
+};
+
+static struct mtk_fixed_factor top_divs[] __initdata = {
+	FACTOR(TOP_MAINPLL_806M, mainpll_806m, mainpll, 1, 2),
+	FACTOR(TOP_MAINPLL_537P3M, mainpll_537p3m, mainpll, 1, 3),
+	FACTOR(TOP_MAINPLL_322P4M, mainpll_322p4m, mainpll, 1, 5),
+	FACTOR(TOP_MAINPLL_230P3M, mainpll_230p3m, mainpll, 1, 7),
+
+	FACTOR(TOP_UNIVPLL_624M, univpll_624m, univpll, 1, 2),
+	FACTOR(TOP_UNIVPLL_416M, univpll_416m, univpll, 1, 3),
+	FACTOR(TOP_UNIVPLL_249P6M, univpll_249p6m, univpll, 1, 5),
+	FACTOR(TOP_UNIVPLL_178P3M, univpll_178p3m, univpll, 1, 7),
+	FACTOR(TOP_UNIVPLL_48M, univpll_48m, univpll, 1, 26),
+
+	FACTOR(TOP_MMPLL_D2, mmpll_d2, mmpll, 1, 2),
+	FACTOR(TOP_MMPLL_D3, mmpll_d3, mmpll, 1, 3),
+	FACTOR(TOP_MMPLL_D5, mmpll_d5, mmpll, 1, 5),
+	FACTOR(TOP_MMPLL_D7, mmpll_d7, mmpll, 1, 7),
+	FACTOR(TOP_MMPLL_D4, mmpll_d4, mmpll_d2, 1, 2),
+	FACTOR(TOP_MMPLL_D6, mmpll_d6, mmpll_d3, 1, 2),
+
+	FACTOR(TOP_SYSPLL_D2, syspll_d2, mainpll_806m, 1, 1),
+	FACTOR(TOP_SYSPLL_D4, syspll_d4, mainpll_806m, 1, 2),
+	FACTOR(TOP_SYSPLL_D6, syspll_d6, mainpll_806m, 1, 3),
+	FACTOR(TOP_SYSPLL_D8, syspll_d8, mainpll_806m, 1, 4),
+	FACTOR(TOP_SYSPLL_D10, syspll_d10, mainpll_806m, 1, 5),
+	FACTOR(TOP_SYSPLL_D12, syspll_d12, mainpll_806m, 1, 6),
+	FACTOR(TOP_SYSPLL_D16, syspll_d16, mainpll_806m, 1, 8),
+	FACTOR(TOP_SYSPLL_D24, syspll_d24, mainpll_806m, 1, 12),
+
+	FACTOR(TOP_SYSPLL_D3, syspll_d3, mainpll_537p3m, 1, 1),
+
+	FACTOR(TOP_SYSPLL_D2P5, syspll_d2p5, mainpll_322p4m, 2, 1),
+	FACTOR(TOP_SYSPLL_D5, syspll_d5, mainpll_322p4m, 1, 1),
+
+	FACTOR(TOP_SYSPLL_D3P5, syspll_d3p5, mainpll_230p3m, 2, 1),
+
+	FACTOR(TOP_UNIVPLL1_D2, univpll1_d2, univpll_624m, 1, 2),
+	FACTOR(TOP_UNIVPLL1_D4, univpll1_d4, univpll_624m, 1, 4),
+	FACTOR(TOP_UNIVPLL1_D6, univpll1_d6, univpll_624m, 1, 6),
+	FACTOR(TOP_UNIVPLL1_D8, univpll1_d8, univpll_624m, 1, 8),
+	FACTOR(TOP_UNIVPLL1_D10, univpll1_d10, univpll_624m, 1, 10),
+
+	FACTOR(TOP_UNIVPLL2_D2, univpll2_d2, univpll_416m, 1, 2),
+	FACTOR(TOP_UNIVPLL2_D4, univpll2_d4, univpll_416m, 1, 4),
+	FACTOR(TOP_UNIVPLL2_D6, univpll2_d6, univpll_416m, 1, 6),
+	FACTOR(TOP_UNIVPLL2_D8, univpll2_d8, univpll_416m, 1, 8),
+
+	FACTOR(TOP_UNIVPLL_D3, univpll_d3, univpll_416m, 1, 1),
+	FACTOR(TOP_UNIVPLL_D5, univpll_d5, univpll_249p6m, 1, 1),
+	FACTOR(TOP_UNIVPLL_D7, univpll_d7, univpll_178p3m, 1, 1),
+	FACTOR(TOP_UNIVPLL_D10, univpll_d10, univpll_249p6m, 1, 5),
+	FACTOR(TOP_UNIVPLL_D26, univpll_d26, univpll_48m, 1, 1),
+
+	FACTOR(TOP_APLL_CK, apll_ck, audpll, 1, 1),
+	FACTOR(TOP_APLL_D4, apll_d4, audpll, 1, 4),
+	FACTOR(TOP_APLL_D8, apll_d8, audpll, 1, 8),
+	FACTOR(TOP_APLL_D16, apll_d16, audpll, 1, 16),
+	FACTOR(TOP_APLL_D24, apll_d24, audpll, 1, 24),
+
+	FACTOR(TOP_LVDSPLL_D2, lvdspll_d2, lvdspll, 1, 2),
+	FACTOR(TOP_LVDSPLL_D4, lvdspll_d4, lvdspll, 1, 4),
+	FACTOR(TOP_LVDSPLL_D8, lvdspll_d8, lvdspll, 1, 8),
+
+	FACTOR(TOP_LVDSTX_CLKDIG_CT, lvdstx_clkdig_cts, lvdspll, 1, 1),
+	FACTOR(TOP_VPLL_DPIX_CK, vpll_dpix_ck, lvdspll, 1, 1),
+
+	FACTOR(TOP_TVHDMI_H_CK, tvhdmi_h_ck, tvdpll, 1, 1),
+
+	FACTOR(TOP_HDMITX_CLKDIG_D2, hdmitx_clkdig_d2, hdmitx_clkdig_cts, 1, 2),
+	FACTOR(TOP_HDMITX_CLKDIG_D3, hdmitx_clkdig_d3, hdmitx_clkdig_cts, 1, 3),
+
+	FACTOR(TOP_TVHDMI_D2, tvhdmi_d2, tvhdmi_h_ck, 1, 2),
+	FACTOR(TOP_TVHDMI_D4, tvhdmi_d4, tvhdmi_h_ck, 1, 4),
+
+	FACTOR(TOP_MEMPLL_MCK_D4, mempll_mck_d4, clkph_mck, 1, 4),
+};
+
+static const char *axi_parents[] __initconst = {
+		clk26m,
+		syspll_d3,
+		syspll_d4,
+		syspll_d6,
+		univpll_d5,
+		univpll2_d2,
+		syspll_d3p5};
+
+static const char *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 *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 *irda_parents[] __initconst = {
+		clk26m,
+		univpll2_d8,
+		univpll1_d6};
+
+static const char *cam_parents[] __initconst = {
+		clk26m,
+		syspll_d3,
+		syspll_d3p5,
+		syspll_d4,
+		univpll_d5,
+		univpll2_d2,
+		univpll_d7,
+		univpll1_d4};
+
+static const char *aud_intbus_parents[] __initconst = {
+		clk26m,
+		syspll_d6,
+		univpll_d10};
+
+static const char *jpg_parents[] __initconst = {
+		clk26m,
+		syspll_d5,
+		syspll_d4,
+		syspll_d3,
+		univpll_d7,
+		univpll2_d2,
+		univpll_d5};
+
+static const char *disp_parents[] __initconst = {
+		clk26m,
+		syspll_d3p5,
+		syspll_d3,
+		univpll2_d2,
+		univpll_d5,
+		univpll1_d2,
+		lvdspll,
+		vdecpll};
+
+static const char *msdc30_parents[] __initconst = {
+		clk26m,
+		syspll_d6,
+		syspll_d5,
+		univpll1_d4,
+		univpll2_d4,
+		msdcpll};
+
+static const char *usb20_parents[] __initconst = {
+		clk26m,
+		univpll2_d6,
+		univpll1_d10};
+
+static const char *venc_parents[] __initconst = {
+		clk26m,
+		syspll_d3,
+		syspll_d8,
+		univpll_d5,
+		univpll1_d6,
+		mmpll_d4,
+		mmpll_d5,
+		mmpll_d6};
+
+static const char *spi_parents[] __initconst = {
+		clk26m,
+		syspll_d6,
+		syspll_d8,
+		syspll_d10,
+		univpll1_d6,
+		univpll1_d8};
+
+static const char *uart_parents[] __initconst = {
+		clk26m,
+		univpll2_d8};
+
+static const char *mem_parents[] __initconst = {
+		clk26m,
+		clkph_mck};
+
+static const char *camtg_parents[] __initconst = {
+		clk26m,
+		univpll_d26,
+		univpll1_d6,
+		syspll_d16,
+		syspll_d8};
+
+static const char *audio_parents[] __initconst = {
+		clk26m,
+		syspll_d24};
+
+static const char *fix_parents[] __initconst = {
+		rtc32k,
+		clk26m,
+		univpll_d5,
+		univpll_d7,
+		univpll1_d2,
+		univpll1_d4,
+		univpll1_d6,
+		univpll1_d8};
+
+static const char *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 *ddrphycfg_parents[] __initconst = {
+		clk26m,
+		axi_sel,
+		syspll_d12};
+
+static const char *dpilvds_parents[] __initconst = {
+		clk26m,
+		lvdspll,
+		lvdspll_d2,
+		lvdspll_d4,
+		lvdspll_d8};
+
+static const char *pmicspi_parents[] __initconst = {
+		clk26m,
+		univpll2_d6,
+		syspll_d8,
+		syspll_d10,
+		univpll1_d10,
+		mempll_mck_d4,
+		univpll_d26,
+		syspll_d24};
+
+static const char *smi_mfg_as_parents[] __initconst = {
+		clk26m,
+		smi_sel,
+		mfg_sel,
+		mem_sel};
+
+static const char *gcpu_parents[] __initconst = {
+		clk26m,
+		syspll_d4,
+		univpll_d7,
+		syspll_d5,
+		syspll_d6};
+
+static const char *dpi1_parents[] __initconst = {
+		clk26m,
+		tvhdmi_h_ck,
+		tvhdmi_d2,
+		tvhdmi_d4};
+
+static const char *cci_parents[] __initconst = {
+		clk26m,
+		mainpll_537p3m,
+		univpll_d3,
+		syspll_d2p5,
+		syspll_d3,
+		syspll_d5};
+
+static const char *apll_parents[] __initconst = {
+		clk26m,
+		apll_ck,
+		apll_d4,
+		apll_d8,
+		apll_d16,
+		apll_d24};
+
+static const char *hdmipll_parents[] __initconst = {
+		clk26m,
+		hdmitx_clkdig_cts,
+		hdmitx_clkdig_d2,
+		hdmitx_clkdig_d3};
+
+static struct mtk_mux top_muxes[] __initdata = {
+	/* CLK_CFG_0 */
+	MUX(TOP_AXI_SEL, axi_sel, axi_parents,
+		0x0140, 0, 3, INVALID_MUX_GATE_BIT),
+	MUX(TOP_SMI_SEL, smi_sel, smi_parents, 0x0140, 8, 4, 15),
+	MUX(TOP_MFG_SEL, mfg_sel, mfg_parents, 0x0140, 16, 4, 23),
+	MUX(TOP_IRDA_SEL, irda_sel, irda_parents, 0x0140, 24, 2, 31),
+	/* CLK_CFG_1 */
+	MUX(TOP_CAM_SEL, cam_sel, cam_parents, 0x0144, 0, 3, 7),
+	MUX(TOP_AUD_INTBUS_SEL, aud_intbus_sel, aud_intbus_parents,
+		0x0144, 8, 2, 15),
+	MUX(TOP_JPG_SEL, jpg_sel, jpg_parents, 0x0144, 16, 3, 23),
+	MUX(TOP_DISP_SEL, disp_sel, disp_parents, 0x0144, 24, 3, 31),
+	/* CLK_CFG_2 */
+	MUX(TOP_MSDC30_1_SEL, msdc30_1_sel, msdc30_parents, 0x0148, 0, 3, 7),
+	MUX(TOP_MSDC30_2_SEL, msdc30_2_sel, msdc30_parents, 0x0148, 8, 3, 15),
+	MUX(TOP_MSDC30_3_SEL, msdc30_3_sel, msdc30_parents, 0x0148, 16, 3, 23),
+	MUX(TOP_MSDC30_4_SEL, msdc30_4_sel, msdc30_parents, 0x0148, 24, 3, 31),
+	/* CLK_CFG_3 */
+	MUX(TOP_USB20_SEL, usb20_sel, usb20_parents, 0x014c, 0, 2, 7),
+	/* CLK_CFG_4 */
+	MUX(TOP_VENC_SEL, venc_sel, venc_parents, 0x0150, 8, 3, 15),
+	MUX(TOP_SPI_SEL, spi_sel, spi_parents, 0x0150, 16, 3, 23),
+	MUX(TOP_UART_SEL, uart_sel, uart_parents, 0x0150, 24, 2, 31),
+	/* CLK_CFG_6 */
+	MUX(TOP_MEM_SEL, mem_sel, mem_parents, 0x0158, 0, 2, 7),
+	MUX(TOP_CAMTG_SEL, camtg_sel, camtg_parents, 0x0158, 8, 3, 15),
+	MUX(TOP_AUDIO_SEL, audio_sel, audio_parents, 0x0158, 24, 2, 31),
+	/* CLK_CFG_7 */
+	MUX(TOP_FIX_SEL, fix_sel, fix_parents, 0x015c, 0, 3, 7),
+	MUX(TOP_VDEC_SEL, vdec_sel, vdec_parents, 0x015c, 8, 4, 15),
+	MUX(TOP_DDRPHYCFG_SEL, ddrphycfg_sel, ddrphycfg_parents,
+		0x015c, 16, 2, 23),
+	MUX(TOP_DPILVDS_SEL, dpilvds_sel, dpilvds_parents, 0x015c, 24, 3, 31),
+	/* CLK_CFG_8 */
+	MUX(TOP_PMICSPI_SEL, pmicspi_sel, pmicspi_parents, 0x0164, 0, 3, 7),
+	MUX(TOP_MSDC30_0_SEL, msdc30_0_sel, msdc30_parents, 0x0164, 8, 3, 15),
+	MUX(TOP_SMI_MFG_AS_SEL, smi_mfg_as_sel, smi_mfg_as_parents,
+		0x0164, 16, 2, 23),
+	MUX(TOP_GCPU_SEL, gcpu_sel, gcpu_parents, 0x0164, 24, 3, 31),
+	/* CLK_CFG_9 */
+	MUX(TOP_DPI1_SEL, dpi1_sel, dpi1_parents, 0x0168, 0, 2, 7),
+	MUX(TOP_CCI_SEL, cci_sel, cci_parents, 0x0168, 8, 3, 15),
+	MUX(TOP_APLL_SEL, apll_sel, apll_parents, 0x0168, 16, 3, 23),
+	MUX(TOP_HDMIPLL_SEL, hdmipll_sel, hdmipll_parents, 0x0168, 24, 2, 31),
+};
+
+static void __init mtk_init_clk_topckgen(void __iomem *top_base,
+		struct clk_onecell_data *clk_data)
+{
+	int i;
+	struct clk *clk;
+
+	for (i = 0; i < ARRAY_SIZE(top_muxes); i++) {
+		struct mtk_mux *mux = &top_muxes[i];
+
+		clk = mtk_clk_register_mux(mux->name,
+			mux->parent_names, mux->num_parents,
+			top_base + mux->reg, mux->shift, mux->width,
+			mux->gate, &lock);
+
+		if (IS_ERR(clk)) {
+			pr_err("Failed to register clk %s: %ld\n",
+					mux->name, PTR_ERR(clk));
+			continue;
+		}
+
+		if (clk_data)
+			clk_data->clks[mux->id] = clk;
+	}
+}
+
+static struct mtk_pll plls[] __initdata = {
+	PLL(APMIXED_ARMPLL1, armpll1, clk26m, 0x0200, 0x0218,
+		0x80000001, HAVE_PLL_HP, &mt8135_arm_pll_ops),
+	PLL(APMIXED_ARMPLL2, armpll2, clk26m, 0x02cc, 0x02e4,
+		0x80000001, HAVE_PLL_HP, &mt8135_arm_pll_ops),
+	PLL(APMIXED_MAINPLL, mainpll, clk26m, 0x021c, 0x0234,
+		0xf0000001, HAVE_PLL_HP | HAVE_RST_BAR | PLL_AO,
+		&mt8135_pll_ops),
+	PLL(APMIXED_UNIVPLL, univpll, clk26m, 0x0238, 0x0250,
+		0xf3000001, HAVE_RST_BAR | HAVE_FIX_FRQ | PLL_AO,
+		&mt8135_lc_pll_ops),
+	PLL(APMIXED_MMPLL, mmpll, clk26m, 0x0254, 0x026c,
+		0xf0000001, HAVE_PLL_HP | HAVE_RST_BAR, &mt8135_pll_ops),
+	PLL(APMIXED_MSDCPLL, msdcpll, clk26m, 0x0278, 0x0290,
+		0x80000001, HAVE_PLL_HP, &mt8135_pll_ops),
+	PLL(APMIXED_TVDPLL, tvdpll, clk26m, 0x0294, 0x02ac,
+		0x80000001, HAVE_PLL_HP, &mt8135_tvd_pll_ops),
+	PLL(APMIXED_LVDSPLL, lvdspll, clk26m, 0x02b0, 0x02c8,
+		0x80000001, HAVE_PLL_HP, &mt8135_pll_ops),
+	PLL(APMIXED_AUDPLL, audpll, clk26m, 0x02e8, 0x0300,
+		0x80000001, 0, &mt8135_aud_pll_ops),
+	PLL(APMIXED_VDECPLL, vdecpll, clk26m, 0x0304, 0x031c,
+		0x80000001, HAVE_PLL_HP, &mt8135_pll_ops),
+};
+
+static void __init mtk_init_clk_apmixedsys(void __iomem *apmixed_base,
+		struct clk_onecell_data *clk_data)
+{
+	int i;
+	struct clk *clk;
+
+	for (i = 0; i < ARRAY_SIZE(plls); i++) {
+		struct mtk_pll *pll = &plls[i];
+
+		clk = mtk_clk_register_pll(pll->name, pll->parent_name,
+				apmixed_base + pll->reg,
+				apmixed_base + pll->pwr_reg,
+				pll->en_mask, pll->flags, pll->ops, &lock);
+
+		if (IS_ERR(clk)) {
+			pr_err("Failed to register clk %s: %ld\n",
+					pll->name, PTR_ERR(clk));
+			continue;
+		}
+
+		if (clk_data)
+			clk_data->clks[pll->id] = clk;
+	}
+}
+
+static struct mtk_gate_regs infra_cg_regs = {
+	.set_ofs = 0x0040,
+	.clr_ofs = 0x0044,
+	.sta_ofs = 0x0048,
+};
+
+static struct mtk_gate infra_clks[] __initdata = {
+	GATE(INFRA_PMIC_WRAP_CK, pmic_wrap_ck, axi_sel, infra_cg_regs,
+		23, &mtk_clk_gate_ops_setclr),
+	GATE(INFRA_PMICSPI_CK, pmicspi_ck, pmicspi_sel, infra_cg_regs,
+		22, &mtk_clk_gate_ops_setclr),
+	GATE(INFRA_CCIF1_AP_CTRL, ccif1_ap_ctrl, axi_sel, infra_cg_regs,
+		21, &mtk_clk_gate_ops_setclr),
+	GATE(INFRA_CCIF0_AP_CTRL, ccif0_ap_ctrl, axi_sel, infra_cg_regs,
+		20, &mtk_clk_gate_ops_setclr),
+	GATE(INFRA_KP_CK, kp_ck, axi_sel, infra_cg_regs,
+		16, &mtk_clk_gate_ops_setclr),
+	GATE(INFRA_CPUM_CK, cpum_ck, cpum_tck_in, infra_cg_regs,
+		15, &mtk_clk_gate_ops_setclr),
+	GATE(INFRA_M4U_CK, m4u_ck, mem_sel, infra_cg_regs,
+		8, &mtk_clk_gate_ops_setclr),
+	GATE(INFRA_MFGAXI_CK, mfgaxi_ck, axi_sel, infra_cg_regs,
+		7, &mtk_clk_gate_ops_setclr),
+	GATE(INFRA_DEVAPC_CK, devapc_ck, axi_sel, infra_cg_regs,
+		6, &mtk_clk_gate_ops_setclr_inv),
+	GATE(INFRA_AUDIO_CK, audio_ck, aud_intbus_sel, infra_cg_regs,
+		5, &mtk_clk_gate_ops_setclr),
+	GATE(INFRA_MFG_BUS_CK, mfg_bus_ck, axi_sel, infra_cg_regs,
+		2, &mtk_clk_gate_ops_setclr),
+	GATE(INFRA_SMI_CK, smi_ck, smi_sel, infra_cg_regs,
+		1, &mtk_clk_gate_ops_setclr),
+	GATE(INFRA_DBGCLK_CK, dbgclk_ck, axi_sel, infra_cg_regs,
+		0, &mtk_clk_gate_ops_setclr),
+};
+
+static struct mtk_gate_regs peri0_cg_regs = {
+	.set_ofs = 0x0008,
+	.clr_ofs = 0x0010,
+	.sta_ofs = 0x0018,
+};
+
+static struct mtk_gate_regs peri1_cg_regs = {
+	.set_ofs = 0x000c,
+	.clr_ofs = 0x0014,
+	.sta_ofs = 0x001c,
+};
+
+static struct mtk_gate peri_clks[] __initdata = {
+	/* PERI0 */
+	GATE(PERI_I2C5_CK, i2c5_ck, axi_sel, peri0_cg_regs,
+		31, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_I2C4_CK, i2c4_ck, axi_sel, peri0_cg_regs,
+		30, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_I2C3_CK, i2c3_ck, axi_sel, peri0_cg_regs,
+		29, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_I2C2_CK, i2c2_ck, axi_sel, peri0_cg_regs,
+		28, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_I2C1_CK, i2c1_ck, axi_sel, peri0_cg_regs,
+		27, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_I2C0_CK, i2c0_ck, axi_sel, peri0_cg_regs,
+		26, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_UART3_CK, uart3_ck, axi_sel, peri0_cg_regs,
+		25, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_UART2_CK, uart2_ck, axi_sel, peri0_cg_regs,
+		24, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_UART1_CK, uart1_ck, axi_sel, peri0_cg_regs,
+		23, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_UART0_CK, uart0_ck, axi_sel, peri0_cg_regs,
+		22, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_IRDA_CK, irda_ck, irda_sel, peri0_cg_regs,
+		21, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_NLI_CK, nli_ck, axi_sel, peri0_cg_regs,
+		20, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_MD_HIF_CK, md_hif_ck, axi_sel, peri0_cg_regs,
+		19, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_AP_HIF_CK, ap_hif_ck, axi_sel, peri0_cg_regs,
+		18, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_MSDC30_3_CK, msdc30_3_ck, msdc30_4_sel, peri0_cg_regs,
+		17, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_MSDC30_2_CK, msdc30_2_ck, msdc30_3_sel, peri0_cg_regs,
+		16, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_MSDC30_1_CK, msdc30_1_ck, msdc30_2_sel, peri0_cg_regs,
+		15, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_MSDC20_2_CK, msdc20_2_ck, msdc30_1_sel, peri0_cg_regs,
+		14, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_MSDC20_1_CK, msdc20_1_ck, msdc30_0_sel, peri0_cg_regs,
+		13, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_AP_DMA_CK, ap_dma_ck, axi_sel, peri0_cg_regs,
+		12, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_USB1_CK, usb1_ck, usb20_sel, peri0_cg_regs,
+		11, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_USB0_CK, usb0_ck, usb20_sel, peri0_cg_regs,
+		10, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_PWM_CK, pwm_ck, axi_sel, peri0_cg_regs,
+		9, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_PWM7_CK, pwm7_ck, axi_sel, peri0_cg_regs,
+		8, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_PWM6_CK, pwm6_ck, axi_sel, peri0_cg_regs,
+		7, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_PWM5_CK, pwm5_ck, axi_sel, peri0_cg_regs,
+		6, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_PWM4_CK, pwm4_ck, axi_sel, peri0_cg_regs,
+		5, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_PWM3_CK, pwm3_ck, axi_sel, peri0_cg_regs,
+		4, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_PWM2_CK, pwm2_ck, axi_sel, peri0_cg_regs,
+		3, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_PWM1_CK, pwm1_ck, axi_sel, peri0_cg_regs,
+		2, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_THERM_CK, therm_ck, axi_sel, peri0_cg_regs,
+		1, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_NFI_CK, nfi_ck, axi_sel, peri0_cg_regs,
+		0, &mtk_clk_gate_ops_setclr),
+	/* PERI1 */
+	GATE(PERI_USBSLV_CK, usbslv_ck, axi_sel, peri1_cg_regs,
+		8, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_USB1_MCU_CK, usb1_mcu_ck, axi_sel, peri1_cg_regs,
+		7, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_USB0_MCU_CK, usb0_mcu_ck, axi_sel, peri1_cg_regs,
+		6, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_GCPU_CK, gcpu_ck, gcpu_sel, peri1_cg_regs,
+		5, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_FHCTL_CK, fhctl_ck, clk26m, peri1_cg_regs,
+		4, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_SPI1_CK, spi1_ck, spi_sel, peri1_cg_regs,
+		3, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_AUXADC_CK, auxadc_ck, clk26m, peri1_cg_regs,
+		2, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_PERI_PWRAP_CK, peri_pwrap_ck, axi_sel, peri1_cg_regs,
+		1, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_I2C6_CK, i2c6_ck, axi_sel, peri1_cg_regs,
+		0, &mtk_clk_gate_ops_setclr),
+};
+
+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(TOP_NR_CLK);
+
+	mtk_init_factors(root_clk_alias, ARRAY_SIZE(root_clk_alias), clk_data);
+	mtk_init_factors(top_divs, ARRAY_SIZE(top_divs), clk_data);
+	mtk_init_clk_topckgen(base, 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);
+}
+CLK_OF_DECLARE(mtk_topckgen, "mediatek,mt8135-topckgen", mtk_topckgen_init);
+
+static void __init mtk_apmixedsys_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(APMIXED_NR_CLK);
+
+	mtk_init_clk_apmixedsys(base, 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);
+}
+CLK_OF_DECLARE(mtk_apmixedsys, "mediatek,mt8135-apmixedsys",
+		mtk_apmixedsys_init);
+
+static void __init mtk_infrasys_init(struct device_node *node)
+{
+	struct clk_onecell_data *clk_data;
+	struct regmap *regmap;
+	int r;
+
+	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;
+	}
+
+	clk_data = mtk_alloc_clk_data(INFRA_NR_CLK);
+
+	mtk_init_clk_gates(regmap, 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,mt8135-infracfg", mtk_infrasys_init);
+
+static void __init mtk_pericfg_init(struct device_node *node)
+{
+	struct clk_onecell_data *clk_data;
+	struct regmap *regmap;
+	int r;
+
+	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;
+	}
+
+	clk_data = mtk_alloc_clk_data(PERI_NR_CLK);
+
+	mtk_init_clk_gates(regmap, peri_clks, ARRAY_SIZE(peri_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, 0);
+}
+CLK_OF_DECLARE(mtk_pericfg, "mediatek,mt8135-pericfg", mtk_pericfg_init);
-- 
2.1.4


^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH 05/13] clk: dts: mediatek: add Mediatek MT8173 clock bindings
  2015-02-09 10:47 [PATCH v5]: clk: Add common clock support for Mediatek MT8135 and MT8173 Sascha Hauer
                   ` (3 preceding siblings ...)
  2015-02-09 10:47 ` [PATCH 04/13] clk: mediatek: Add basic clocks for Mediatek MT8135 Sascha Hauer
@ 2015-02-09 10:47 ` Sascha Hauer
  2015-02-09 10:47 ` [PATCH 06/13] clk: mediatek: Add basic clocks for Mediatek MT8173 Sascha Hauer
                   ` (7 subsequent siblings)
  12 siblings, 0 replies; 27+ messages in thread
From: Sascha Hauer @ 2015-02-09 10:47 UTC (permalink / raw)
  To: Matthias Brugger
  Cc: linux-arm-kernel, linux-kernel, Rob Herring, Eddie Huang,
	Lee Jones, Yingjoe Chen (陳英洲),
	Henry Chen, YH Chen (陳昱豪),
	kernel, Mike Turquette, James Liao, Sascha Hauer

From: James Liao <jamesjj.liao@mediatek.com>

Document the device-tree binding of Mediatek MT8173 SoC, including
TOPCKGEN, PLLs, INFRA and PERI clock controller.

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>
---
 .../bindings/clock/mediatek,mt8173-clock.txt       |  42 ++++
 include/dt-bindings/clock/mt8173-clk.h             | 214 +++++++++++++++++++++
 2 files changed, 256 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/mediatek,mt8173-clock.txt
 create mode 100644 include/dt-bindings/clock/mt8173-clk.h

diff --git a/Documentation/devicetree/bindings/clock/mediatek,mt8173-clock.txt b/Documentation/devicetree/bindings/clock/mediatek,mt8173-clock.txt
new file mode 100644
index 0000000..15cd49a
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/mediatek,mt8173-clock.txt
@@ -0,0 +1,42 @@
+Mediatek MT8173 Clock Controller
+
+This binding uses the common clock binding:
+Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+The Mediatek MT8173 clock controller generates and supplies clock to various
+controllers within Mediatek MT8173 SoC.
+
+Required Properties:
+
+- compatible: should be one of following:
+	- "mediatek,mt8173-topckgen" : for topckgen clock controller of MT8173.
+	- "mediatek,mt8173-apmixedsys" : for apmixed_sys (PLLs) of MT8173.
+	- "mediatek,mt8173-infrasys" : for infra_sys clock controller of MT8173.
+	- "mediatek,mt8173-pericfg" : for peri_sys clock controller of MT8173.
+
+- reg: physical base address of the controller and length of memory mapped
+  region.
+
+- #clock-cells: should be 1.
+
+All available clocks are defined as preprocessor macros in
+dt-bindings/clock/mt8173-clk.h header and can be used in device tree sources.
+
+Example: I2C controller node that consumes the clock generated by the clock
+  controller (refer to the standard clock bindings for information about
+  "clocks" and "clock-names" properties):
+
+	pericfg: pericfg@10003000 {
+		compatible = "mediatek,mt8173-pericfg";
+		reg = <0 0x10003000 0 0x1000>;
+		#clock-cells = <1>;
+	};
+
+	i2c0: i2c@1100d000 {
+		compatible = "mediatek,mt8173-i2c", "mediatek,mt6589-i2c";
+		reg = <0 0x1100d000 0 0x70>, <0 0x11000300 0 0x80>;
+		interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_LOW>;
+		clock-div = <16>;
+		clocks = <&pericfg PERI_I2C0>, <&pericfg PERI_AP_DMA>;
+		clock-names = "main", "dma";
+	};
diff --git a/include/dt-bindings/clock/mt8173-clk.h b/include/dt-bindings/clock/mt8173-clk.h
new file mode 100644
index 0000000..f3f1d13
--- /dev/null
+++ b/include/dt-bindings/clock/mt8173-clk.h
@@ -0,0 +1,214 @@
+/*
+ * 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 TOP_CLKPH_MCK_O		1
+#define TOP_DPI_CK		2
+#define TOP_USB_SYSPLL_125M	3
+#define TOP_HDMITX_DIG_CTS	4
+#define TOP_ARMCA7PLL_754M	5
+#define TOP_ARMCA7PLL_502M	6
+#define TOP_MAIN_H546M		7
+#define TOP_MAIN_H364M		8
+#define TOP_MAIN_H218P4M	9
+#define TOP_MAIN_H156M		10
+#define TOP_TVDPLL_445P5M	11
+#define TOP_TVDPLL_594M		12
+#define TOP_UNIV_624M		13
+#define TOP_UNIV_416M		14
+#define TOP_UNIV_249P6M		15
+#define TOP_UNIV_178P3M		16
+#define TOP_UNIV_48M		17
+#define TOP_CLKRTC_EXT		18
+#define TOP_CLKRTC_INT		19
+#define TOP_FPC_CK		20
+#define TOP_HDMITXPLL_D2	21
+#define TOP_HDMITXPLL_D3	22
+#define TOP_ARMCA7PLL_D2	23
+#define TOP_ARMCA7PLL_D3	24
+#define TOP_APLL1_CK		25
+#define TOP_APLL2_CK		26
+#define TOP_DMPLL_CK		27
+#define TOP_DMPLL_D2		28
+#define TOP_DMPLL_D4		29
+#define TOP_DMPLL_D8		30
+#define TOP_DMPLL_D16		31
+#define TOP_LVDSPLL_D2		32
+#define TOP_LVDSPLL_D4		33
+#define TOP_LVDSPLL_D8		34
+#define TOP_MMPLL_CK		35
+#define TOP_MMPLL_D2		36
+#define TOP_MSDCPLL_CK		37
+#define TOP_MSDCPLL_D2		38
+#define TOP_MSDCPLL_D4		39
+#define TOP_MSDCPLL2_CK		40
+#define TOP_MSDCPLL2_D2		41
+#define TOP_MSDCPLL2_D4		42
+#define TOP_SYSPLL_D2		43
+#define TOP_SYSPLL1_D2		44
+#define TOP_SYSPLL1_D4		45
+#define TOP_SYSPLL1_D8		46
+#define TOP_SYSPLL1_D16		47
+#define TOP_SYSPLL_D3		48
+#define TOP_SYSPLL2_D2		49
+#define TOP_SYSPLL2_D4		50
+#define TOP_SYSPLL_D5		51
+#define TOP_SYSPLL3_D2		52
+#define TOP_SYSPLL3_D4		53
+#define TOP_SYSPLL_D7		54
+#define TOP_SYSPLL4_D2		55
+#define TOP_SYSPLL4_D4		56
+#define TOP_TVDPLL_CK		57
+#define TOP_TVDPLL_D2		58
+#define TOP_TVDPLL_D4		59
+#define TOP_TVDPLL_D8		60
+#define TOP_TVDPLL_D16		61
+#define TOP_UNIVPLL_D2		62
+#define TOP_UNIVPLL1_D2		63
+#define TOP_UNIVPLL1_D4		64
+#define TOP_UNIVPLL1_D8		65
+#define TOP_UNIVPLL_D3		66
+#define TOP_UNIVPLL2_D2		67
+#define TOP_UNIVPLL2_D4		68
+#define TOP_UNIVPLL2_D8		69
+#define TOP_UNIVPLL_D5		70
+#define TOP_UNIVPLL3_D2		71
+#define TOP_UNIVPLL3_D4		72
+#define TOP_UNIVPLL3_D8		73
+#define TOP_UNIVPLL_D7		74
+#define TOP_UNIVPLL_D26		75
+#define TOP_UNIVPLL_D52		76
+#define TOP_VCODECPLL_CK	77
+#define TOP_VCODECPLL_370P5	78
+#define TOP_VENCPLL_CK		79
+#define TOP_VENCPLL_D2		80
+#define TOP_VENCPLL_D4		81
+#define TOP_AXI_SEL		82
+#define TOP_MEM_SEL		83
+#define TOP_DDRPHYCFG_SEL	84
+#define TOP_MM_SEL		85
+#define TOP_PWM_SEL		86
+#define TOP_VDEC_SEL		87
+#define TOP_VENC_SEL		88
+#define TOP_MFG_SEL		89
+#define TOP_CAMTG_SEL		90
+#define TOP_UART_SEL		91
+#define TOP_SPI_SEL		92
+#define TOP_USB20_SEL		93
+#define TOP_USB30_SEL		94
+#define TOP_MSDC50_0_H_SEL	95
+#define TOP_MSDC50_0_SEL	96
+#define TOP_MSDC30_1_SEL	97
+#define TOP_MSDC30_2_SEL	98
+#define TOP_MSDC30_3_SEL	99
+#define TOP_AUDIO_SEL		100
+#define TOP_AUD_INTBUS_SEL	101
+#define TOP_PMICSPI_SEL		102
+#define TOP_SCP_SEL		103
+#define TOP_ATB_SEL		104
+#define TOP_VENC_LT_SEL		105
+#define TOP_DPI0_SEL		106
+#define TOP_IRDA_SEL		107
+#define TOP_CCI400_SEL		108
+#define TOP_AUD_1_SEL		109
+#define TOP_AUD_2_SEL		110
+#define TOP_MEM_MFG_IN_SEL	111
+#define TOP_AXI_MFG_IN_SEL	112
+#define TOP_SCAM_SEL		113
+#define TOP_SPINFI_IFR_SEL	114
+#define TOP_HDMI_SEL		115
+#define TOP_DPILVDS_SEL		116
+#define TOP_MSDC50_2_H_SEL	117
+#define TOP_HDCP_SEL		118
+#define TOP_HDCP_24M_SEL	119
+#define TOP_RTC_SEL		120
+#define TOP_NR_CLK		121
+
+/* APMIXED_SYS */
+
+#define APMIXED_ARMCA15PLL	1
+#define APMIXED_ARMCA7PLL	2
+#define APMIXED_MAINPLL		3
+#define APMIXED_UNIVPLL		4
+#define APMIXED_MMPLL		5
+#define APMIXED_MSDCPLL		6
+#define APMIXED_VENCPLL		7
+#define APMIXED_TVDPLL		8
+#define APMIXED_MPLL		9
+#define APMIXED_VCODECPLL	10
+#define APMIXED_APLL1		11
+#define APMIXED_APLL2		12
+#define APMIXED_LVDSPLL		13
+#define APMIXED_MSDCPLL2	14
+#define APMIXED_NR_CLK		15
+
+/* INFRA_SYS */
+
+#define INFRA_DBGCLK		1
+#define INFRA_SMI		2
+#define INFRA_AUDIO		3
+#define INFRA_GCE		4
+#define INFRA_L2C_SRAM		5
+#define INFRA_M4U		6
+#define INFRA_CPUM		7
+#define INFRA_KP		8
+#define INFRA_CEC		9
+#define INFRA_PMICSPI		10
+#define INFRA_PMICWRAP		11
+#define INFRA_NR_CLK		12
+
+/* PERI_SYS */
+
+#define PERI_NFI		1
+#define PERI_THERM		2
+#define PERI_PWM1		3
+#define PERI_PWM2		4
+#define PERI_PWM3		5
+#define PERI_PWM4		6
+#define PERI_PWM5		7
+#define PERI_PWM6		8
+#define PERI_PWM7		9
+#define PERI_PWM		10
+#define PERI_USB0		11
+#define PERI_USB1		12
+#define PERI_AP_DMA		13
+#define PERI_MSDC30_0		14
+#define PERI_MSDC30_1		15
+#define PERI_MSDC30_2		16
+#define PERI_MSDC30_3		17
+#define PERI_NLI_ARB		18
+#define PERI_IRDA		19
+#define PERI_UART0		20
+#define PERI_UART1		21
+#define PERI_UART2		22
+#define PERI_UART3		23
+#define PERI_I2C0		24
+#define PERI_I2C1		25
+#define PERI_I2C2		26
+#define PERI_I2C3		27
+#define PERI_I2C4		28
+#define PERI_AUXADC		29
+#define PERI_SPI0		30
+#define PERI_I2C5		31
+#define PERI_NFIECC		32
+#define PERI_SPI		33
+#define PERI_IRRX		34
+#define PERI_I2C6		35
+#define PERI_NR_CLK		36
+
+#endif /* _DT_BINDINGS_CLK_MT8173_H */
-- 
2.1.4


^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH 06/13] clk: mediatek: Add basic clocks for Mediatek MT8173.
  2015-02-09 10:47 [PATCH v5]: clk: Add common clock support for Mediatek MT8135 and MT8173 Sascha Hauer
                   ` (4 preceding siblings ...)
  2015-02-09 10:47 ` [PATCH 05/13] clk: dts: mediatek: add Mediatek MT8173 clock bindings Sascha Hauer
@ 2015-02-09 10:47 ` Sascha Hauer
  2015-02-13  9:56   ` Tomasz Figa
  2015-02-09 10:47 ` [PATCH 07/13] dt: bindings: Add MediaTek MT8135/MT8173 reset controller defines Sascha Hauer
                   ` (6 subsequent siblings)
  12 siblings, 1 reply; 27+ messages in thread
From: Sascha Hauer @ 2015-02-09 10:47 UTC (permalink / raw)
  To: Matthias Brugger
  Cc: linux-arm-kernel, linux-kernel, Rob Herring, Eddie Huang,
	Lee Jones, Yingjoe Chen (陳英洲),
	Henry Chen, YH Chen (陳昱豪),
	kernel, Mike Turquette, James Liao, Sascha Hauer

From: James Liao <jamesjj.liao@mediatek.com>

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-pll.c |  807 +++++++++++++++++++++++++
 drivers/clk/mediatek/clk-mt8173-pll.h |   14 +
 drivers/clk/mediatek/clk-mt8173.c     | 1035 +++++++++++++++++++++++++++++++++
 4 files changed, 1857 insertions(+)
 create mode 100644 drivers/clk/mediatek/clk-mt8173-pll.c
 create mode 100644 drivers/clk/mediatek/clk-mt8173-pll.h
 create mode 100644 drivers/clk/mediatek/clk-mt8173.c

diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile
index afb52e5..e030416 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 clk-mt8135-pll.o
+obj-y += clk-mt8173.o clk-mt8173-pll.o
diff --git a/drivers/clk/mediatek/clk-mt8173-pll.c b/drivers/clk/mediatek/clk-mt8173-pll.c
new file mode 100644
index 0000000..9f6f821
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mt8173-pll.c
@@ -0,0 +1,807 @@
+/*
+ * 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/io.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/clkdev.h>
+
+#include "clk-mtk.h"
+#include "clk-pll.h"
+#include "clk-mt8173-pll.h"
+
+#define PLL_BASE_EN	BIT(0)
+#define PLL_PWR_ON	BIT(0)
+#define PLL_ISO_EN	BIT(1)
+#define PLL_PCW_CHG	BIT(31)
+#define RST_BAR_MASK	BIT(24)
+#define AUDPLL_TUNER_EN	BIT(31)
+
+static const u32 pll_posdiv_map[8] = { 1, 2, 4, 8, 16, 16, 16, 16 };
+
+static u32 mtk_calc_pll_vco_freq(
+		u32 fin,
+		u32 pcw,
+		u32 vcodivsel,
+		u32 prediv,
+		u32 pcwfbits)
+{
+	/* vco = (fin * pcw * vcodivsel / prediv) >> pcwfbits; */
+	u64 vco = fin;
+	u8 c = 0;
+
+	vco = vco * pcw * vcodivsel;
+	do_div(vco, prediv);
+
+	if (vco & GENMASK(pcwfbits - 1, 0))
+		c = 1;
+
+	vco >>= pcwfbits;
+
+	if (c)
+		++vco;
+
+	return (u32)vco;
+}
+
+static u32 mtk_freq_limit(u32 freq)
+{
+	static const u64 freq_max = 3000UL * 1000 * 1000;	/* 3000 MHz */
+	static const u32 freq_min = 1000 * 1000 * 1000 / 16;	/* 62.5 MHz */
+
+	if (freq <= freq_min)
+		freq = freq_min + 16;
+	else if (freq > freq_max)
+		freq = freq_max;
+
+	return freq;
+}
+
+static int mtk_calc_pll_freq_cfg(
+		u32 *pcw,
+		u32 *postdiv_idx,
+		u32 freq,
+		u32 fin,
+		int pcwfbits)
+{
+	static const u64 freq_max = 3000UL * 1000 * 1000;	/* 3000 MHz */
+	static const u64 freq_min = 1000 * 1000 * 1000;		/* 1000 MHz */
+	static const u64 postdiv[] = { 1, 2, 4, 8, 16 };
+	u64 n_info;
+	u32 idx;
+
+	/* search suitable postdiv */
+	for (idx = *postdiv_idx;
+		idx < ARRAY_SIZE(postdiv) && postdiv[idx] * freq <= freq_min;
+		idx++)
+		;
+
+	if (idx >= ARRAY_SIZE(postdiv))
+		return -EINVAL;	/* freq is out of range (too low) */
+	else if (postdiv[idx] * freq > freq_max)
+		return -EINVAL;	/* freq is out of range (too high) */
+
+	/* n_info = freq * postdiv / 26MHz * 2^pcwfbits */
+	n_info = (postdiv[idx] * freq) << pcwfbits;
+	do_div(n_info, fin);
+
+	*postdiv_idx = idx;
+	*pcw = (u32)n_info;
+
+	return 0;
+}
+
+static int mtk_clk_pll_is_enabled(struct clk_hw *hw)
+{
+	struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
+
+	return (readl_relaxed(pll->base_addr) & PLL_BASE_EN) != 0;
+}
+
+static int mtk_clk_pll_prepare(struct clk_hw *hw)
+{
+	unsigned long flags = 0;
+	struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
+	u32 r;
+
+	spin_lock_irqsave(pll->lock, flags);
+
+	r = readl_relaxed(pll->pwr_addr) | PLL_PWR_ON;
+	writel_relaxed(r, pll->pwr_addr);
+	wmb();	/* sync write before delay */
+	udelay(1);
+
+	r = readl_relaxed(pll->pwr_addr) & ~PLL_ISO_EN;
+	writel_relaxed(r, pll->pwr_addr);
+	wmb();	/* sync write before delay */
+	udelay(1);
+
+	r = readl_relaxed(pll->base_addr) | pll->en_mask;
+	writel_relaxed(r, pll->base_addr);
+	wmb();	/* sync write before delay */
+	udelay(20);
+
+	if (pll->flags & HAVE_RST_BAR) {
+		r = readl_relaxed(pll->base_addr) | RST_BAR_MASK;
+		writel_relaxed(r, pll->base_addr);
+	}
+
+	spin_unlock_irqrestore(pll->lock, flags);
+
+	return 0;
+}
+
+static void mtk_clk_pll_unprepare(struct clk_hw *hw)
+{
+	unsigned long flags = 0;
+	struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
+	u32 r;
+
+	if (pll->flags & PLL_AO)
+		return;
+
+	spin_lock_irqsave(pll->lock, flags);
+
+	if (pll->flags & HAVE_RST_BAR) {
+		r = readl_relaxed(pll->base_addr) & ~RST_BAR_MASK;
+		writel_relaxed(r, pll->base_addr);
+	}
+
+	r = readl_relaxed(pll->base_addr) & ~PLL_BASE_EN;
+	writel_relaxed(r, pll->base_addr);
+
+	r = readl_relaxed(pll->pwr_addr) | PLL_ISO_EN;
+	writel_relaxed(r, pll->pwr_addr);
+
+	r = readl_relaxed(pll->pwr_addr) & ~PLL_PWR_ON;
+	writel_relaxed(r, pll->pwr_addr);
+
+	spin_unlock_irqrestore(pll->lock, flags);
+}
+
+static long mtk_clk_pll_round_rate(
+		struct clk_hw *hw,
+		unsigned long rate,
+		unsigned long *prate)
+{
+	u32 pcwfbits = 14;
+	u32 pcw = 0;
+	u32 postdiv = 0;
+	u32 r;
+
+	*prate = *prate ? *prate : 26000000;
+	rate = mtk_freq_limit(rate);
+	mtk_calc_pll_freq_cfg(&pcw, &postdiv, rate, *prate, pcwfbits);
+
+	r = mtk_calc_pll_vco_freq(*prate, pcw, 1, 1, pcwfbits);
+	r = (r + pll_posdiv_map[postdiv] - 1) / pll_posdiv_map[postdiv];
+
+	return r;
+}
+
+#define SDM_PLL_POSTDIV_H	6
+#define SDM_PLL_POSTDIV_L	4
+#define SDM_PLL_POSTDIV_MASK	GENMASK(SDM_PLL_POSTDIV_H, SDM_PLL_POSTDIV_L)
+#define SDM_PLL_PCW_H		20
+#define SDM_PLL_PCW_L		0
+#define SDM_PLL_PCW_MASK	GENMASK(SDM_PLL_PCW_H, SDM_PLL_PCW_L)
+
+static unsigned long mtk_clk_sdm_pll_recalc_rate(
+		struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
+
+	u32 con0 = readl_relaxed(pll->base_addr);
+	u32 con1 = readl_relaxed(pll->base_addr + 4);
+
+	u32 posdiv = (con0 & SDM_PLL_POSTDIV_MASK) >> SDM_PLL_POSTDIV_L;
+	u32 pcw = (con1 & SDM_PLL_PCW_MASK) >> SDM_PLL_PCW_L;
+	u32 pcwfbits = 14;
+
+	u32 vco_freq;
+	unsigned long r;
+
+	parent_rate = parent_rate ? parent_rate : 26000000;
+
+	vco_freq = mtk_calc_pll_vco_freq(parent_rate, pcw, 1, 1, pcwfbits);
+	r = (vco_freq + pll_posdiv_map[posdiv] - 1) / pll_posdiv_map[posdiv];
+
+	return r;
+}
+
+static void mtk_clk_sdm_pll_set_rate_regs(
+		struct clk_hw *hw,
+		u32 pcw,
+		u32 postdiv_idx)
+{
+	unsigned long flags = 0;
+	struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
+	void __iomem *con0_addr = pll->base_addr;
+	void __iomem *con1_addr = pll->base_addr + 4;
+	u32 con0;
+	u32 con1;
+	u32 pll_en;
+
+	spin_lock_irqsave(pll->lock, flags);
+
+	con0 = readl_relaxed(con0_addr);
+	con1 = readl_relaxed(con1_addr);
+
+	pll_en = con0 & PLL_BASE_EN;
+
+	/* set postdiv */
+	con0 &= ~SDM_PLL_POSTDIV_MASK;
+	con0 |= postdiv_idx << SDM_PLL_POSTDIV_L;
+	writel_relaxed(con0, con0_addr);
+
+	/* set pcw */
+	con1 &= ~SDM_PLL_PCW_MASK;
+	con1 |= pcw << SDM_PLL_PCW_L;
+
+	if (pll_en)
+		con1 |= PLL_PCW_CHG;
+
+	writel_relaxed(con1, con1_addr);
+
+	if (pll_en) {
+		wmb();	/* sync write before delay */
+		udelay(20);
+	}
+
+	spin_unlock_irqrestore(pll->lock, flags);
+}
+
+static int mtk_clk_sdm_pll_set_rate(
+		struct clk_hw *hw,
+		unsigned long rate,
+		unsigned long parent_rate)
+{
+	u32 pcwfbits = 14;
+	u32 pcw = 0;
+	u32 postdiv_idx = 0;
+	int r;
+
+	parent_rate = parent_rate ? parent_rate : 26000000;
+	r = mtk_calc_pll_freq_cfg(&pcw, &postdiv_idx, rate,
+			parent_rate, pcwfbits);
+
+	if (r == 0)
+		mtk_clk_sdm_pll_set_rate_regs(hw, pcw, postdiv_idx);
+
+	return r;
+}
+
+const struct clk_ops mt8173_sdm_pll_ops = {
+	.is_enabled	= mtk_clk_pll_is_enabled,
+	.prepare	= mtk_clk_pll_prepare,
+	.unprepare	= mtk_clk_pll_unprepare,
+	.recalc_rate	= mtk_clk_sdm_pll_recalc_rate,
+	.round_rate	= mtk_clk_pll_round_rate,
+	.set_rate	= mtk_clk_sdm_pll_set_rate,
+};
+
+#define ARM_PLL_POSTDIV_H	26
+#define ARM_PLL_POSTDIV_L	24
+#define ARM_PLL_POSTDIV_MASK	GENMASK(ARM_PLL_POSTDIV_H, ARM_PLL_POSTDIV_L)
+#define ARM_PLL_PCW_H		20
+#define ARM_PLL_PCW_L		0
+#define ARM_PLL_PCW_MASK	GENMASK(ARM_PLL_PCW_H, ARM_PLL_PCW_L)
+
+static unsigned long mtk_clk_arm_pll_recalc_rate(
+		struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
+
+	u32 con1 = readl_relaxed(pll->base_addr + 4);
+
+	u32 posdiv = (con1 & ARM_PLL_POSTDIV_MASK) >> ARM_PLL_POSTDIV_L;
+	u32 pcw = (con1 & ARM_PLL_PCW_MASK) >> ARM_PLL_PCW_L;
+	u32 pcwfbits = 14;
+
+	u32 vco_freq;
+	unsigned long r;
+
+	parent_rate = parent_rate ? parent_rate : 26000000;
+
+	vco_freq = mtk_calc_pll_vco_freq(parent_rate, pcw, 1, 1, pcwfbits);
+	r = (vco_freq + pll_posdiv_map[posdiv] - 1) / pll_posdiv_map[posdiv];
+
+	return r;
+}
+
+static void mtk_clk_arm_pll_set_rate_regs(
+		struct clk_hw *hw,
+		u32 pcw,
+		u32 postdiv_idx)
+
+{
+	unsigned long flags = 0;
+	struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
+	void __iomem *con0_addr = pll->base_addr;
+	void __iomem *con1_addr = pll->base_addr + 4;
+	u32 con0;
+	u32 con1;
+	u32 pll_en;
+
+	spin_lock_irqsave(pll->lock, flags);
+
+	con0 = readl_relaxed(con0_addr);
+	con1 = readl_relaxed(con1_addr);
+
+	pll_en = con0 & PLL_BASE_EN;
+
+	/* postdiv */
+	con1 &= ~ARM_PLL_POSTDIV_MASK;
+	con1 |= postdiv_idx << ARM_PLL_POSTDIV_L;
+
+	/* pcw */
+	con1 &= ~ARM_PLL_PCW_MASK;
+	con1 |= pcw << ARM_PLL_PCW_L;
+
+	if (pll_en)
+		con1 |= PLL_PCW_CHG;
+
+	writel_relaxed(con1, con1_addr);
+
+	if (pll_en) {
+		wmb();	/* sync write before delay */
+		udelay(20);
+	}
+
+	spin_unlock_irqrestore(pll->lock, flags);
+}
+
+static int mtk_clk_arm_pll_set_rate(
+		struct clk_hw *hw,
+		unsigned long rate,
+		unsigned long parent_rate)
+{
+	u32 pcwfbits = 14;
+	u32 pcw = 0;
+	u32 postdiv_idx = 0;
+	int r;
+
+	parent_rate = parent_rate ? parent_rate : 26000000;
+	r = mtk_calc_pll_freq_cfg(&pcw, &postdiv_idx, rate,
+			parent_rate, pcwfbits);
+
+	if (r == 0)
+		mtk_clk_arm_pll_set_rate_regs(hw, pcw, postdiv_idx);
+
+	return r;
+}
+
+const struct clk_ops mt8173_arm_pll_ops = {
+	.is_enabled	= mtk_clk_pll_is_enabled,
+	.prepare	= mtk_clk_pll_prepare,
+	.unprepare	= mtk_clk_pll_unprepare,
+	.recalc_rate	= mtk_clk_arm_pll_recalc_rate,
+	.round_rate	= mtk_clk_pll_round_rate,
+	.set_rate	= mtk_clk_arm_pll_set_rate,
+};
+
+static long mtk_clk_mm_pll_round_rate(
+		struct clk_hw *hw,
+		unsigned long rate,
+		unsigned long *prate)
+{
+	u32 pcwfbits = 14;
+	u32 pcw = 0;
+	u32 postdiv = 0;
+	u32 r;
+
+	if (rate <= 702000000)
+		postdiv = 2;
+
+	*prate = *prate ? *prate : 26000000;
+	rate = mtk_freq_limit(rate);
+	mtk_calc_pll_freq_cfg(&pcw, &postdiv, rate, *prate, pcwfbits);
+
+	r = mtk_calc_pll_vco_freq(*prate, pcw, 1, 1, pcwfbits);
+	r = (r + pll_posdiv_map[postdiv] - 1) / pll_posdiv_map[postdiv];
+
+	return r;
+}
+
+static int mtk_clk_mm_pll_set_rate(
+		struct clk_hw *hw,
+		unsigned long rate,
+		unsigned long parent_rate)
+{
+	u32 pcwfbits = 14;
+	u32 pcw = 0;
+	u32 postdiv_idx = 0;
+	int r;
+
+	if (rate <= 702000000)
+		postdiv_idx = 2;
+
+	parent_rate = parent_rate ? parent_rate : 26000000;
+	r = mtk_calc_pll_freq_cfg(&pcw, &postdiv_idx, rate,
+			parent_rate, pcwfbits);
+
+	if (r == 0)
+		mtk_clk_arm_pll_set_rate_regs(hw, pcw, postdiv_idx);
+
+	return r;
+}
+
+const struct clk_ops mt8173_mm_pll_ops = {
+	.is_enabled	= mtk_clk_pll_is_enabled,
+	.prepare	= mtk_clk_pll_prepare,
+	.unprepare	= mtk_clk_pll_unprepare,
+	.recalc_rate	= mtk_clk_arm_pll_recalc_rate,
+	.round_rate	= mtk_clk_mm_pll_round_rate,
+	.set_rate	= mtk_clk_mm_pll_set_rate,
+};
+
+static int mtk_clk_univ_pll_prepare(struct clk_hw *hw)
+{
+	unsigned long flags = 0;
+	struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
+	u32 r;
+
+	spin_lock_irqsave(pll->lock, flags);
+
+	r = readl_relaxed(pll->base_addr) | pll->en_mask;
+	writel_relaxed(r, pll->base_addr);
+	wmb();	/* sync write before delay */
+	udelay(20);
+
+	if (pll->flags & HAVE_RST_BAR) {
+		r = readl_relaxed(pll->base_addr) | RST_BAR_MASK;
+		writel_relaxed(r, pll->base_addr);
+	}
+
+	spin_unlock_irqrestore(pll->lock, flags);
+
+	return 0;
+}
+
+static void mtk_clk_univ_pll_unprepare(struct clk_hw *hw)
+{
+	unsigned long flags = 0;
+	struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
+	u32 r;
+
+	if (pll->flags & PLL_AO)
+		return;
+
+	spin_lock_irqsave(pll->lock, flags);
+
+	if (pll->flags & HAVE_RST_BAR) {
+		r = readl_relaxed(pll->base_addr) & ~RST_BAR_MASK;
+		writel_relaxed(r, pll->base_addr);
+	}
+
+	r = readl_relaxed(pll->base_addr) & ~PLL_BASE_EN;
+	writel_relaxed(r, pll->base_addr);
+
+	spin_unlock_irqrestore(pll->lock, flags);
+}
+
+#define UNIV_PLL_POSTDIV_H	6
+#define UNIV_PLL_POSTDIV_L	4
+#define UNIV_PLL_POSTDIV_MASK	GENMASK(UNIV_PLL_POSTDIV_H, UNIV_PLL_POSTDIV_L)
+#define UNIV_PLL_FBKDIV_H	20
+#define UNIV_PLL_FBKDIV_L	14
+#define UNIV_PLL_FBKDIV_MASK	GENMASK(UNIV_PLL_FBKDIV_H, UNIV_PLL_FBKDIV_L)
+
+static unsigned long mtk_clk_univ_pll_recalc_rate(
+		struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
+
+	u32 con0 = readl_relaxed(pll->base_addr);
+	u32 con1 = readl_relaxed(pll->base_addr + 4);
+
+	u32 fbkdiv = (con1 & UNIV_PLL_FBKDIV_MASK) >> UNIV_PLL_FBKDIV_L;
+	u32 posdiv = (con0 & UNIV_PLL_POSTDIV_MASK) >> UNIV_PLL_POSTDIV_L;
+
+	u32 vco_freq;
+	unsigned long r;
+
+	parent_rate = parent_rate ? parent_rate : 26000000;
+
+	vco_freq = parent_rate * fbkdiv;
+	r = (vco_freq + pll_posdiv_map[posdiv] - 1) / pll_posdiv_map[posdiv];
+
+	return r;
+}
+
+static void mtk_clk_univ_pll_set_rate_regs(
+		struct clk_hw *hw,
+		u32 pcw,
+		u32 postdiv_idx)
+{
+	unsigned long flags = 0;
+	struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
+	void __iomem *con0_addr = pll->base_addr;
+	void __iomem *con1_addr = pll->base_addr + 4;
+	u32 con0;
+	u32 con1;
+	u32 pll_en;
+
+	spin_lock_irqsave(pll->lock, flags);
+
+	con0 = readl_relaxed(con0_addr);
+	con1 = readl_relaxed(con1_addr);
+
+	pll_en = con0 & PLL_BASE_EN;
+
+	/* postdiv */
+	con0 &= ~UNIV_PLL_POSTDIV_MASK;
+	con0 |= postdiv_idx << UNIV_PLL_POSTDIV_L;
+
+	/* fkbdiv */
+	con1 &= ~UNIV_PLL_FBKDIV_MASK;
+	con1 |= pcw << UNIV_PLL_FBKDIV_L;
+
+	writel_relaxed(con0, con0_addr);
+	writel_relaxed(con1, con1_addr);
+
+	if (pll_en) {
+		wmb();	/* sync write before delay */
+		udelay(20);
+	}
+
+	spin_unlock_irqrestore(pll->lock, flags);
+}
+
+static long mtk_clk_univ_pll_round_rate(
+		struct clk_hw *hw,
+		unsigned long rate,
+		unsigned long *prate)
+{
+	u32 pcwfbits = 0;
+	u32 pcw = 0;
+	u32 postdiv = 0;
+	u32 r;
+
+	*prate = *prate ? *prate : 26000000;
+	rate = mtk_freq_limit(rate);
+	mtk_calc_pll_freq_cfg(&pcw, &postdiv, rate, *prate, pcwfbits);
+
+	r = *prate * pcw;
+	r = (r + pll_posdiv_map[postdiv] - 1) / pll_posdiv_map[postdiv];
+
+	return r;
+}
+
+static int mtk_clk_univ_pll_set_rate(
+		struct clk_hw *hw,
+		unsigned long rate,
+		unsigned long parent_rate)
+{
+	u32 pcwfbits = 0;
+	u32 pcw = 0;
+	u32 postdiv_idx = 0;
+	int r;
+
+	parent_rate = parent_rate ? parent_rate : 26000000;
+	r = mtk_calc_pll_freq_cfg(&pcw, &postdiv_idx, rate,
+			parent_rate, pcwfbits);
+
+	if (r == 0)
+		mtk_clk_univ_pll_set_rate_regs(hw, pcw, postdiv_idx);
+
+	return r;
+}
+
+const struct clk_ops mt8173_univ_pll_ops = {
+	.is_enabled	= mtk_clk_pll_is_enabled,
+	.prepare	= mtk_clk_univ_pll_prepare,
+	.unprepare	= mtk_clk_univ_pll_unprepare,
+	.recalc_rate	= mtk_clk_univ_pll_recalc_rate,
+	.round_rate	= mtk_clk_univ_pll_round_rate,
+	.set_rate	= mtk_clk_univ_pll_set_rate,
+};
+
+static int mtk_clk_aud_pll_prepare(struct clk_hw *hw)
+{
+	unsigned long flags = 0;
+	struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
+	void __iomem *con0_addr = pll->base_addr;
+	void __iomem *con2_addr = pll->base_addr + 8;
+	u32 r;
+
+	spin_lock_irqsave(pll->lock, flags);
+
+	r = readl_relaxed(pll->pwr_addr) | PLL_PWR_ON;
+	writel_relaxed(r, pll->pwr_addr);
+	wmb();	/* sync write before delay */
+	udelay(1);
+
+	r = readl_relaxed(pll->pwr_addr) & ~PLL_ISO_EN;
+	writel_relaxed(r, pll->pwr_addr);
+	wmb();	/* sync write before delay */
+	udelay(1);
+
+	r = readl_relaxed(con0_addr) | pll->en_mask;
+	writel_relaxed(r, con0_addr);
+
+	r = readl_relaxed(con2_addr) | AUDPLL_TUNER_EN;
+	writel_relaxed(r, con2_addr);
+	wmb();	/* sync write before delay */
+	udelay(20);
+
+	if (pll->flags & HAVE_RST_BAR) {
+		r = readl_relaxed(con0_addr) | RST_BAR_MASK;
+		writel_relaxed(r, con0_addr);
+	}
+
+	spin_unlock_irqrestore(pll->lock, flags);
+
+	return 0;
+}
+
+static void mtk_clk_aud_pll_unprepare(struct clk_hw *hw)
+{
+	unsigned long flags = 0;
+	struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
+	void __iomem *con0_addr = pll->base_addr;
+	void __iomem *con2_addr = pll->base_addr + 8;
+	u32 r;
+
+	if (pll->flags & PLL_AO)
+		return;
+
+	spin_lock_irqsave(pll->lock, flags);
+
+	if (pll->flags & HAVE_RST_BAR) {
+		r = readl_relaxed(con0_addr) & ~RST_BAR_MASK;
+		writel_relaxed(r, con0_addr);
+	}
+
+	r = readl_relaxed(con2_addr) & ~AUDPLL_TUNER_EN;
+	writel_relaxed(r, con2_addr);
+
+	r = readl_relaxed(con0_addr) & ~PLL_BASE_EN;
+	writel_relaxed(r, con0_addr);
+
+	r = readl_relaxed(pll->pwr_addr) | PLL_ISO_EN;
+	writel_relaxed(r, pll->pwr_addr);
+
+	r = readl_relaxed(pll->pwr_addr) & ~PLL_PWR_ON;
+	writel_relaxed(r, pll->pwr_addr);
+
+	spin_unlock_irqrestore(pll->lock, flags);
+}
+
+#define AUD_PLL_POSTDIV_H	6
+#define AUD_PLL_POSTDIV_L	4
+#define AUD_PLL_POSTDIV_MASK	GENMASK(AUD_PLL_POSTDIV_H, AUD_PLL_POSTDIV_L)
+#define AUD_PLL_PCW_H		30
+#define AUD_PLL_PCW_L		0
+#define AUD_PLL_PCW_MASK	GENMASK(AUD_PLL_PCW_H, AUD_PLL_PCW_L)
+
+static unsigned long mtk_clk_aud_pll_recalc_rate(
+		struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
+
+	u32 con0 = readl_relaxed(pll->base_addr);
+	u32 con1 = readl_relaxed(pll->base_addr + 4);
+
+	u32 posdiv = (con0 & AUD_PLL_POSTDIV_MASK) >> AUD_PLL_POSTDIV_L;
+	u32 pcw = (con1 & AUD_PLL_PCW_MASK) >> AUD_PLL_PCW_L;
+	u32 pcwfbits = 24;
+
+	u32 vco_freq;
+	unsigned long r;
+
+	parent_rate = parent_rate ? parent_rate : 26000000;
+
+	vco_freq = mtk_calc_pll_vco_freq(parent_rate, pcw, 1, 1, pcwfbits);
+	r = (vco_freq + pll_posdiv_map[posdiv] - 1) / pll_posdiv_map[posdiv];
+
+	return r;
+}
+
+static void mtk_clk_aud_pll_set_rate_regs(
+		struct clk_hw *hw,
+		u32 pcw,
+		u32 postdiv_idx)
+{
+	unsigned long flags = 0;
+	struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
+	void __iomem *con0_addr = pll->base_addr;
+	void __iomem *con1_addr = pll->base_addr + 4;
+	void __iomem *con2_addr = pll->base_addr + 8;
+	u32 con0;
+	u32 con1;
+	u32 pll_en;
+
+	spin_lock_irqsave(pll->lock, flags);
+
+	con0 = readl_relaxed(con0_addr);
+	con1 = readl_relaxed(con1_addr);
+
+	pll_en = con0 & PLL_BASE_EN;
+
+	/* set postdiv */
+	con0 &= ~AUD_PLL_POSTDIV_MASK;
+	con0 |= postdiv_idx << AUD_PLL_POSTDIV_L;
+	writel_relaxed(con0, con0_addr);
+
+	/* set pcw */
+	con1 &= ~AUD_PLL_PCW_MASK;
+	con1 |= pcw << AUD_PLL_PCW_L;
+
+	if (pll_en)
+		con1 |= PLL_PCW_CHG;
+
+	writel_relaxed(con1, con1_addr);
+	writel_relaxed(con1 + 1, con2_addr);
+
+	if (pll_en) {
+		wmb();	/* sync write before delay */
+		udelay(20);
+	}
+
+	spin_unlock_irqrestore(pll->lock, flags);
+}
+
+static long mtk_clk_aud_pll_round_rate(
+		struct clk_hw *hw,
+		unsigned long rate,
+		unsigned long *prate)
+{
+	u32 pcwfbits = 24;
+	u32 pcw = 0;
+	u32 postdiv = 0;
+	u32 r;
+
+	*prate = *prate ? *prate : 26000000;
+	rate = mtk_freq_limit(rate);
+	mtk_calc_pll_freq_cfg(&pcw, &postdiv, rate, *prate, pcwfbits);
+
+	r = mtk_calc_pll_vco_freq(*prate, pcw, 1, 1, pcwfbits);
+	r = (r + pll_posdiv_map[postdiv] - 1) / pll_posdiv_map[postdiv];
+
+	return r;
+}
+
+static int mtk_clk_aud_pll_set_rate(
+		struct clk_hw *hw,
+		unsigned long rate,
+		unsigned long parent_rate)
+{
+	u32 pcwfbits = 24;
+	u32 pcw = 0;
+	u32 postdiv_idx = 0;
+	int r;
+
+	parent_rate = parent_rate ? parent_rate : 26000000;
+	r = mtk_calc_pll_freq_cfg(&pcw, &postdiv_idx, rate,
+			parent_rate, pcwfbits);
+
+	if (r == 0)
+		mtk_clk_aud_pll_set_rate_regs(hw, pcw, postdiv_idx);
+
+	return r;
+}
+
+const struct clk_ops mt8173_aud_pll_ops = {
+	.is_enabled	= mtk_clk_pll_is_enabled,
+	.prepare	= mtk_clk_aud_pll_prepare,
+	.unprepare	= mtk_clk_aud_pll_unprepare,
+	.recalc_rate	= mtk_clk_aud_pll_recalc_rate,
+	.round_rate	= mtk_clk_aud_pll_round_rate,
+	.set_rate	= mtk_clk_aud_pll_set_rate,
+};
diff --git a/drivers/clk/mediatek/clk-mt8173-pll.h b/drivers/clk/mediatek/clk-mt8173-pll.h
new file mode 100644
index 0000000..663ab4b
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mt8173-pll.h
@@ -0,0 +1,14 @@
+#ifndef __DRV_CLK_MT8173_PLL_H
+#define __DRV_CLK_MT8173_PLL_H
+
+/*
+ * This is a private header file. DO NOT include it except clk-*.c.
+ */
+
+extern const struct clk_ops mt8173_sdm_pll_ops;
+extern const struct clk_ops mt8173_arm_pll_ops;
+extern const struct clk_ops mt8173_mm_pll_ops;
+extern const struct clk_ops mt8173_univ_pll_ops;
+extern const struct clk_ops mt8173_aud_pll_ops;
+
+#endif /* __DRV_CLK_MT8173_PLL_H */
diff --git a/drivers/clk/mediatek/clk-mt8173.c b/drivers/clk/mediatek/clk-mt8173.c
new file mode 100644
index 0000000..d75e591
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mt8173.c
@@ -0,0 +1,1035 @@
+/*
+ * 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-pll.h"
+#include "clk-gate.h"
+#include "clk-mt8173-pll.h"
+
+#include <dt-bindings/clock/mt8173-clk.h>
+
+/* ROOT */
+#define clk_null		"clk_null"
+#define clk26m			"clk26m"
+#define clk32k			"clk32k"
+
+#define clkph_mck_o		"clkph_mck_o"
+#define dpi_ck			"dpi_ck"
+#define usb_syspll_125m		"usb_syspll_125m"
+#define hdmitx_dig_cts		"hdmitx_dig_cts"
+
+/* PLL */
+#define armca15pll		"armca15pll"
+#define armca7pll		"armca7pll"
+#define mainpll			"mainpll"
+#define univpll			"univpll"
+#define mmpll			"mmpll"
+#define msdcpll			"msdcpll"
+#define vencpll			"vencpll"
+#define tvdpll			"tvdpll"
+#define mpll			"mpll"
+#define vcodecpll		"vcodecpll"
+#define apll1			"apll1"
+#define apll2			"apll2"
+#define lvdspll			"lvdspll"
+#define msdcpll2		"msdcpll2"
+
+#define armca7pll_754m		"armca7pll_754m"
+#define armca7pll_502m		"armca7pll_502m"
+#define apll1_180p633m		apll1
+#define apll2_196p608m		apll2
+#define mmpll_455m		mmpll
+#define msdcpll_806m		msdcpll
+#define main_h546m		"main_h546m"
+#define main_h364m		"main_h364m"
+#define main_h218p4m		"main_h218p4m"
+#define main_h156m		"main_h156m"
+#define tvdpll_445p5m		"tvdpll_445p5m"
+#define tvdpll_594m		"tvdpll_594m"
+#define univ_624m		"univ_624m"
+#define univ_416m		"univ_416m"
+#define univ_249p6m		"univ_249p6m"
+#define univ_178p3m		"univ_178p3m"
+#define univ_48m		"univ_48m"
+#define vcodecpll_370p5		"vcodecpll_370p5"
+#define vcodecpll_494m		vcodecpll
+#define vencpll_380m		vencpll
+#define lvdspll_ck		lvdspll
+
+/* DIV */
+#define clkrtc_ext		"clkrtc_ext"
+#define clkrtc_int		"clkrtc_int"
+#define fpc_ck			"fpc_ck"
+#define hdmitxpll_d2		"hdmitxpll_d2"
+#define hdmitxpll_d3		"hdmitxpll_d3"
+#define armca7pll_d2		"armca7pll_d2"
+#define armca7pll_d3		"armca7pll_d3"
+#define apll1_ck		"apll1_ck"
+#define apll2_ck		"apll2_ck"
+#define dmpll_ck		"dmpll_ck"
+#define dmpll_d2		"dmpll_d2"
+#define dmpll_d4		"dmpll_d4"
+#define dmpll_d8		"dmpll_d8"
+#define dmpll_d16		"dmpll_d16"
+#define lvdspll_d2		"lvdspll_d2"
+#define lvdspll_d4		"lvdspll_d4"
+#define lvdspll_d8		"lvdspll_d8"
+#define mmpll_ck		"mmpll_ck"
+#define mmpll_d2		"mmpll_d2"
+#define msdcpll_ck		"msdcpll_ck"
+#define msdcpll_d2		"msdcpll_d2"
+#define msdcpll_d4		"msdcpll_d4"
+#define msdcpll2_ck		"msdcpll2_ck"
+#define msdcpll2_d2		"msdcpll2_d2"
+#define msdcpll2_d4		"msdcpll2_d4"
+#define ssusb_phyd_125m_ck	usb_syspll_125m
+#define syspll_d2		"syspll_d2"
+#define syspll1_d2		"syspll1_d2"
+#define syspll1_d4		"syspll1_d4"
+#define syspll1_d8		"syspll1_d8"
+#define syspll1_d16		"syspll1_d16"
+#define syspll_d3		"syspll_d3"
+#define syspll2_d2		"syspll2_d2"
+#define syspll2_d4		"syspll2_d4"
+#define syspll_d5		"syspll_d5"
+#define syspll3_d2		"syspll3_d2"
+#define syspll3_d4		"syspll3_d4"
+#define syspll_d7		"syspll_d7"
+#define syspll4_d2		"syspll4_d2"
+#define syspll4_d4		"syspll4_d4"
+#define tvdpll_445p5m_ck	tvdpll_445p5m
+#define tvdpll_ck		"tvdpll_ck"
+#define tvdpll_d2		"tvdpll_d2"
+#define tvdpll_d4		"tvdpll_d4"
+#define tvdpll_d8		"tvdpll_d8"
+#define tvdpll_d16		"tvdpll_d16"
+#define univpll_d2		"univpll_d2"
+#define univpll1_d2		"univpll1_d2"
+#define univpll1_d4		"univpll1_d4"
+#define univpll1_d8		"univpll1_d8"
+#define univpll_d3		"univpll_d3"
+#define univpll2_d2		"univpll2_d2"
+#define univpll2_d4		"univpll2_d4"
+#define univpll2_d8		"univpll2_d8"
+#define univpll_d5		"univpll_d5"
+#define univpll3_d2		"univpll3_d2"
+#define univpll3_d4		"univpll3_d4"
+#define univpll3_d8		"univpll3_d8"
+#define univpll_d7		"univpll_d7"
+#define univpll_d26		"univpll_d26"
+#define univpll_d52		"univpll_d52"
+#define vcodecpll_ck		"vcodecpll_ck"
+#define vencpll_ck		"vencpll_ck"
+#define vencpll_d2		"vencpll_d2"
+#define vencpll_d4		"vencpll_d4"
+
+/* TOP */
+#define axi_sel			"axi_sel"
+#define mem_sel			"mem_sel"
+#define ddrphycfg_sel		"ddrphycfg_sel"
+#define mm_sel			"mm_sel"
+#define pwm_sel			"pwm_sel"
+#define vdec_sel		"vdec_sel"
+#define venc_sel		"venc_sel"
+#define mfg_sel			"mfg_sel"
+#define camtg_sel		"camtg_sel"
+#define uart_sel		"uart_sel"
+#define spi_sel			"spi_sel"
+#define usb20_sel		"usb20_sel"
+#define usb30_sel		"usb30_sel"
+#define msdc50_0_h_sel		"msdc50_0_h_sel"
+#define msdc50_0_sel		"msdc50_0_sel"
+#define msdc30_1_sel		"msdc30_1_sel"
+#define msdc30_2_sel		"msdc30_2_sel"
+#define msdc30_3_sel		"msdc30_3_sel"
+#define audio_sel		"audio_sel"
+#define aud_intbus_sel		"aud_intbus_sel"
+#define pmicspi_sel		"pmicspi_sel"
+#define scp_sel			"scp_sel"
+#define atb_sel			"atb_sel"
+#define venclt_sel		"venclt_sel"
+#define dpi0_sel		"dpi0_sel"
+#define irda_sel		"irda_sel"
+#define cci400_sel		"cci400_sel"
+#define aud_1_sel		"aud_1_sel"
+#define aud_2_sel		"aud_2_sel"
+#define mem_mfg_in_sel		"mem_mfg_in_sel"
+#define axi_mfg_in_sel		"axi_mfg_in_sel"
+#define scam_sel		"scam_sel"
+#define spinfi_ifr_sel		"spinfi_ifr_sel"
+#define hdmi_sel		"hdmi_sel"
+#define dpilvds_sel		"dpilvds_sel"
+#define msdc50_2_h_sel		"msdc50_2_h_sel"
+#define hdcp_sel		"hdcp_sel"
+#define hdcp_24m_sel		"hdcp_24m_sel"
+#define rtc_sel			"rtc_sel"
+
+#define axi_ck			axi_sel
+#define mfg_ck			mfg_sel
+
+/* INFRA */
+#define infra_pmicwrap		"infra_pmicwrap"
+#define infra_pmicspi		"infra_pmicspi"
+#define infra_cec		"infra_cec"
+#define infra_kp		"infra_kp"
+#define infra_cpum		"infra_cpum"
+#define infra_m4u		"infra_m4u"
+#define infra_l2c_sram		"infra_l2c_sram"
+#define infra_gce		"infra_gce"
+#define infra_audio		"infra_audio"
+#define infra_smi		"infra_smi"
+#define infra_dbgclk		"infra_dbgclk"
+
+/* PERI0 */
+#define peri_nfiecc		"peri_nfiecc"
+#define peri_i2c5		"peri_i2c5"
+#define peri_spi0		"peri_spi0"
+#define peri_auxadc		"peri_auxadc"
+#define peri_i2c4		"peri_i2c4"
+#define peri_i2c3		"peri_i2c3"
+#define peri_i2c2		"peri_i2c2"
+#define peri_i2c1		"peri_i2c1"
+#define peri_i2c0		"peri_i2c0"
+#define peri_uart3		"peri_uart3"
+#define peri_uart2		"peri_uart2"
+#define peri_uart1		"peri_uart1"
+#define peri_uart0		"peri_uart0"
+#define peri_irda		"peri_irda"
+#define peri_nli_arb		"peri_nli_arb"
+#define peri_msdc30_3		"peri_msdc30_3"
+#define peri_msdc30_2		"peri_msdc30_2"
+#define peri_msdc30_1		"peri_msdc30_1"
+#define peri_msdc30_0		"peri_msdc30_0"
+#define peri_ap_dma		"peri_ap_dma"
+#define peri_usb1		"peri_usb1"
+#define peri_usb0		"peri_usb0"
+#define peri_pwm		"peri_pwm"
+#define peri_pwm7		"peri_pwm7"
+#define peri_pwm6		"peri_pwm6"
+#define peri_pwm5		"peri_pwm5"
+#define peri_pwm4		"peri_pwm4"
+#define peri_pwm3		"peri_pwm3"
+#define peri_pwm2		"peri_pwm2"
+#define peri_pwm1		"peri_pwm1"
+#define peri_therm		"peri_therm"
+#define peri_nfi		"peri_nfi"
+
+/* PERI1 */
+#define peri_i2c6		"peri_i2c6"
+#define peri_irrx		"peri_irrx"
+#define peri_spi		"peri_spi"
+
+static DEFINE_SPINLOCK(lock);
+
+static struct mtk_fixed_factor root_clk_alias[] __initdata = {
+	FACTOR(TOP_CLKPH_MCK_O, clkph_mck_o, clk_null, 1, 1),
+	FACTOR(TOP_DPI_CK, dpi_ck, clk_null, 1, 1),
+	FACTOR(TOP_USB_SYSPLL_125M, usb_syspll_125m, clk_null, 1, 1),
+	FACTOR(TOP_HDMITX_DIG_CTS, hdmitx_dig_cts, clk_null, 1, 1),
+};
+
+static struct mtk_fixed_factor top_divs[] __initdata = {
+	FACTOR(TOP_ARMCA7PLL_754M, armca7pll_754m, armca7pll, 1, 2),
+	FACTOR(TOP_ARMCA7PLL_502M, armca7pll_502m, armca7pll, 1, 3),
+
+	FACTOR(TOP_MAIN_H546M, main_h546m, mainpll, 1, 2),
+	FACTOR(TOP_MAIN_H364M, main_h364m, mainpll, 1, 3),
+	FACTOR(TOP_MAIN_H218P4M, main_h218p4m, mainpll, 1, 5),
+	FACTOR(TOP_MAIN_H156M, main_h156m, mainpll, 1, 7),
+
+	FACTOR(TOP_TVDPLL_445P5M, tvdpll_445p5m, tvdpll, 1, 4),
+	FACTOR(TOP_TVDPLL_594M, tvdpll_594m, tvdpll, 1, 3),
+
+	FACTOR(TOP_UNIV_624M, univ_624m, univpll, 1, 2),
+	FACTOR(TOP_UNIV_416M, univ_416m, univpll, 1, 3),
+	FACTOR(TOP_UNIV_249P6M, univ_249p6m, univpll, 1, 5),
+	FACTOR(TOP_UNIV_178P3M, univ_178p3m, univpll, 1, 7),
+	FACTOR(TOP_UNIV_48M, univ_48m, univpll, 1, 26),
+
+	FACTOR(TOP_CLKRTC_EXT, clkrtc_ext, clk32k, 1, 1),
+	FACTOR(TOP_CLKRTC_INT, clkrtc_int, clk26m, 1, 793),
+	FACTOR(TOP_FPC_CK, fpc_ck, clk26m, 1, 1),
+
+	FACTOR(TOP_HDMITXPLL_D2, hdmitxpll_d2, hdmitx_dig_cts, 1, 2),
+	FACTOR(TOP_HDMITXPLL_D3, hdmitxpll_d3, hdmitx_dig_cts, 1, 3),
+
+	FACTOR(TOP_ARMCA7PLL_D2, armca7pll_d2, armca7pll_754m, 1, 1),
+	FACTOR(TOP_ARMCA7PLL_D3, armca7pll_d3, armca7pll_502m, 1, 1),
+
+	FACTOR(TOP_APLL1_CK, apll1_ck, apll1_180p633m, 1, 1),
+	FACTOR(TOP_APLL2_CK, apll2_ck, apll2_196p608m, 1, 1),
+
+	FACTOR(TOP_DMPLL_CK, dmpll_ck, clkph_mck_o, 1, 1),
+	FACTOR(TOP_DMPLL_D2, dmpll_d2, clkph_mck_o, 1, 2),
+	FACTOR(TOP_DMPLL_D4, dmpll_d4, clkph_mck_o, 1, 4),
+	FACTOR(TOP_DMPLL_D8, dmpll_d8, clkph_mck_o, 1, 8),
+	FACTOR(TOP_DMPLL_D16, dmpll_d16, clkph_mck_o, 1, 16),
+
+	FACTOR(TOP_LVDSPLL_D2, lvdspll_d2, lvdspll, 1, 2),
+	FACTOR(TOP_LVDSPLL_D4, lvdspll_d4, lvdspll, 1, 4),
+	FACTOR(TOP_LVDSPLL_D8, lvdspll_d8, lvdspll, 1, 8),
+
+	FACTOR(TOP_MMPLL_CK, mmpll_ck, mmpll_455m, 1, 1),
+	FACTOR(TOP_MMPLL_D2, mmpll_d2, mmpll_455m, 1, 2),
+
+	FACTOR(TOP_MSDCPLL_CK, msdcpll_ck, msdcpll_806m, 1, 1),
+	FACTOR(TOP_MSDCPLL_D2, msdcpll_d2, msdcpll_806m, 1, 2),
+	FACTOR(TOP_MSDCPLL_D4, msdcpll_d4, msdcpll_806m, 1, 4),
+	FACTOR(TOP_MSDCPLL2_CK, msdcpll2_ck, msdcpll2, 1, 1),
+	FACTOR(TOP_MSDCPLL2_D2, msdcpll2_d2, msdcpll2, 1, 2),
+	FACTOR(TOP_MSDCPLL2_D4, msdcpll2_d4, msdcpll2, 1, 4),
+
+	FACTOR(TOP_SYSPLL_D2, syspll_d2, main_h546m, 1, 1),
+	FACTOR(TOP_SYSPLL1_D2, syspll1_d2, main_h546m, 1, 2),
+	FACTOR(TOP_SYSPLL1_D4, syspll1_d4, main_h546m, 1, 4),
+	FACTOR(TOP_SYSPLL1_D8, syspll1_d8, main_h546m, 1, 8),
+	FACTOR(TOP_SYSPLL1_D16, syspll1_d16, main_h546m, 1, 16),
+	FACTOR(TOP_SYSPLL_D3, syspll_d3, main_h364m, 1, 1),
+	FACTOR(TOP_SYSPLL2_D2, syspll2_d2, main_h364m, 1, 2),
+	FACTOR(TOP_SYSPLL2_D4, syspll2_d4, main_h364m, 1, 4),
+	FACTOR(TOP_SYSPLL_D5, syspll_d5, main_h218p4m, 1, 1),
+	FACTOR(TOP_SYSPLL3_D2, syspll3_d2, main_h218p4m, 1, 2),
+	FACTOR(TOP_SYSPLL3_D4, syspll3_d4, main_h218p4m, 1, 4),
+	FACTOR(TOP_SYSPLL_D7, syspll_d7, main_h156m, 1, 1),
+	FACTOR(TOP_SYSPLL4_D2, syspll4_d2, main_h156m, 1, 2),
+	FACTOR(TOP_SYSPLL4_D4, syspll4_d4, main_h156m, 1, 4),
+
+	FACTOR(TOP_TVDPLL_CK, tvdpll_ck, tvdpll_594m, 1, 1),
+	FACTOR(TOP_TVDPLL_D2, tvdpll_d2, tvdpll_594m, 1, 2),
+	FACTOR(TOP_TVDPLL_D4, tvdpll_d4, tvdpll_594m, 1, 4),
+	FACTOR(TOP_TVDPLL_D8, tvdpll_d8, tvdpll_594m, 1, 8),
+	FACTOR(TOP_TVDPLL_D16, tvdpll_d16, tvdpll_594m, 1, 16),
+
+	FACTOR(TOP_UNIVPLL_D2, univpll_d2, univ_624m, 1, 1),
+	FACTOR(TOP_UNIVPLL1_D2, univpll1_d2, univ_624m, 1, 2),
+	FACTOR(TOP_UNIVPLL1_D4, univpll1_d4, univ_624m, 1, 4),
+	FACTOR(TOP_UNIVPLL1_D8, univpll1_d8, univ_624m, 1, 8),
+	FACTOR(TOP_UNIVPLL_D3, univpll_d3, univ_416m, 1, 1),
+	FACTOR(TOP_UNIVPLL2_D2, univpll2_d2, univ_416m, 1, 2),
+	FACTOR(TOP_UNIVPLL2_D4, univpll2_d4, univ_416m, 1, 4),
+	FACTOR(TOP_UNIVPLL2_D8, univpll2_d8, univ_416m, 1, 8),
+	FACTOR(TOP_UNIVPLL_D5, univpll_d5, univ_249p6m, 1, 1),
+	FACTOR(TOP_UNIVPLL3_D2, univpll3_d2, univ_249p6m, 1, 2),
+	FACTOR(TOP_UNIVPLL3_D4, univpll3_d4, univ_249p6m, 1, 4),
+	FACTOR(TOP_UNIVPLL3_D8, univpll3_d8, univ_249p6m, 1, 8),
+	FACTOR(TOP_UNIVPLL_D7, univpll_d7, univ_178p3m, 1, 1),
+	FACTOR(TOP_UNIVPLL_D26, univpll_d26, univ_48m, 1, 1),
+	FACTOR(TOP_UNIVPLL_D52, univpll_d52, univ_48m, 1, 2),
+
+	FACTOR(TOP_VCODECPLL_CK, vcodecpll_ck, vcodecpll, 1, 3),
+	FACTOR(TOP_VCODECPLL_370P5, vcodecpll_370p5, vcodecpll, 1, 4),
+
+	FACTOR(TOP_VENCPLL_CK, vencpll_ck, vencpll_380m, 1, 1),
+	FACTOR(TOP_VENCPLL_D2, vencpll_d2, vencpll_380m, 1, 2),
+	FACTOR(TOP_VENCPLL_D4, vencpll_d4, vencpll_380m, 1, 4),
+};
+
+static const char *axi_parents[] __initconst = {
+		clk26m,
+		syspll1_d2,
+		syspll_d5,
+		syspll1_d4,
+		univpll_d5,
+		univpll2_d2,
+		dmpll_d2,
+		dmpll_d4};
+
+static const char *mem_parents[] __initconst = {
+		clk26m,
+		dmpll_ck};
+
+static const char *ddrphycfg_parents[] __initconst = {
+		clk26m,
+		syspll1_d8};
+
+static const char *mm_parents[] __initconst = {
+		clk26m,
+		vencpll_d2,
+		main_h364m,
+		syspll1_d2,
+		syspll_d5,
+		syspll1_d4,
+		univpll1_d2,
+		univpll2_d2,
+		dmpll_d2};
+
+static const char *pwm_parents[] __initconst = {
+		clk26m,
+		univpll2_d4,
+		univpll3_d2,
+		univpll1_d4};
+
+static const char *vdec_parents[] __initconst = {
+		clk26m,
+		vcodecpll_ck,
+		tvdpll_445p5m_ck,
+		univpll_d3,
+		vencpll_d2,
+		syspll_d3,
+		univpll1_d2,
+		mmpll_d2,
+		dmpll_d2,
+		dmpll_d4};
+
+static const char *venc_parents[] __initconst = {
+		clk26m,
+		vcodecpll_ck,
+		tvdpll_445p5m_ck,
+		univpll_d3,
+		vencpll_d2,
+		syspll_d3,
+		univpll1_d2,
+		univpll2_d2,
+		dmpll_d2,
+		dmpll_d4};
+
+static const char *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 *camtg_parents[] __initconst = {
+		clk26m,
+		univpll_d26,
+		univpll2_d2,
+		syspll3_d2,
+		syspll3_d4,
+		univpll1_d4};
+
+static const char *uart_parents[] __initconst = {
+		clk26m,
+		univpll2_d8};
+
+static const char *spi_parents[] __initconst = {
+		clk26m,
+		syspll3_d2,
+		syspll1_d4,
+		syspll4_d2,
+		univpll3_d2,
+		univpll2_d4,
+		univpll1_d8};
+
+static const char *usb20_parents[] __initconst = {
+		clk26m,
+		univpll1_d8,
+		univpll3_d4};
+
+static const char *usb30_parents[] __initconst = {
+		clk26m,
+		univpll3_d2,
+		ssusb_phyd_125m_ck,
+		univpll2_d4};
+
+static const char *msdc50_0_h_parents[] __initconst = {
+		clk26m,
+		syspll1_d2,
+		syspll2_d2,
+		syspll4_d2,
+		univpll_d5,
+		univpll1_d4};
+
+static const char *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 *msdc30_1_parents[] __initconst = {
+		clk26m,
+		univpll2_d2,
+		msdcpll_d4,
+		univpll1_d4,
+		syspll2_d2,
+		syspll_d7,
+		univpll_d7,
+		vencpll_d4};
+
+static const char *msdc30_2_parents[] __initconst = {
+		clk26m,
+		univpll2_d2,
+		msdcpll_d4,
+		univpll1_d4,
+		syspll2_d2,
+		syspll_d7,
+		univpll_d7,
+		vencpll_d2};
+
+static const char *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 *audio_parents[] __initconst = {
+		clk26m,
+		syspll3_d4,
+		syspll4_d4,
+		syspll1_d16};
+
+static const char *aud_intbus_parents[] __initconst = {
+		clk26m,
+		syspll1_d4,
+		syspll4_d2,
+		univpll3_d2,
+		univpll2_d8,
+		dmpll_d4,
+		dmpll_d8};
+
+static const char *pmicspi_parents[] __initconst = {
+		clk26m,
+		syspll1_d8,
+		syspll3_d4,
+		syspll1_d16,
+		univpll3_d4,
+		univpll_d26,
+		dmpll_d8,
+		dmpll_d16};
+
+static const char *scp_parents[] __initconst = {
+		clk26m,
+		syspll1_d2,
+		univpll_d5,
+		syspll_d5,
+		dmpll_d2,
+		dmpll_d4};
+
+static const char *atb_parents[] __initconst = {
+		clk26m,
+		syspll1_d2,
+		univpll_d5,
+		dmpll_d2};
+
+static const char *venc_lt_parents[] __initconst = {
+		clk26m,
+		univpll_d3,
+		vcodecpll_ck,
+		tvdpll_445p5m_ck,
+		vencpll_d2,
+		syspll_d3,
+		univpll1_d2,
+		univpll2_d2,
+		syspll1_d2,
+		univpll_d5,
+		vcodecpll_370p5,
+		dmpll_ck};
+
+static const char *dpi0_parents[] __initconst = {
+		clk26m,
+		tvdpll_d2,
+		tvdpll_d4,
+		clk26m,
+		clk26m,
+		tvdpll_d8,
+		tvdpll_d16};
+
+static const char *irda_parents[] __initconst = {
+		clk26m,
+		univpll2_d4,
+		syspll2_d4};
+
+static const char *cci400_parents[] __initconst = {
+		clk26m,
+		vencpll_ck,
+		armca7pll_754m,
+		armca7pll_502m,
+		univpll_d2,
+		syspll_d2,
+		msdcpll_ck,
+		dmpll_ck};
+
+static const char *aud_1_parents[] __initconst = {
+		clk26m,
+		apll1_ck,
+		univpll2_d4,
+		univpll2_d8};
+
+static const char *aud_2_parents[] __initconst = {
+		clk26m,
+		apll2_ck,
+		univpll2_d4,
+		univpll2_d8};
+
+static const char *mem_mfg_in_parents[] __initconst = {
+		clk26m,
+		mmpll_ck,
+		dmpll_ck,
+		clk26m};
+
+static const char *axi_mfg_in_parents[] __initconst = {
+		clk26m,
+		axi_ck,
+		dmpll_d2};
+
+static const char *scam_parents[] __initconst = {
+		clk26m,
+		syspll3_d2,
+		univpll2_d4,
+		dmpll_d4};
+
+static const char *spinfi_ifr_parents[] __initconst = {
+		clk26m,
+		univpll2_d8,
+		univpll3_d4,
+		syspll4_d2,
+		univpll2_d4,
+		univpll3_d2,
+		syspll1_d4,
+		univpll1_d4};
+
+static const char *hdmi_parents[] __initconst = {
+		clk26m,
+		hdmitx_dig_cts,
+		hdmitxpll_d2,
+		hdmitxpll_d3};
+
+static const char *dpilvds_parents[] __initconst = {
+		clk26m,
+		lvdspll_ck,
+		lvdspll_d2,
+		lvdspll_d4,
+		lvdspll_d8,
+		fpc_ck};
+
+static const char *msdc50_2_h_parents[] __initconst = {
+		clk26m,
+		syspll1_d2,
+		syspll2_d2,
+		syspll4_d2,
+		univpll_d5,
+		univpll1_d4};
+
+static const char *hdcp_parents[] __initconst = {
+		clk26m,
+		syspll4_d2,
+		syspll3_d4,
+		univpll2_d4};
+
+static const char *hdcp_24m_parents[] __initconst = {
+		clk26m,
+		univpll_d26,
+		univpll_d52,
+		univpll2_d8};
+
+static const char *rtc_parents[] __initconst = {
+		clkrtc_int,
+		clkrtc_ext,
+		clk26m,
+		univpll3_d8};
+
+static struct mtk_mux top_muxes[] __initdata = {
+	/* CLK_CFG_0 */
+	MUX(TOP_AXI_SEL, axi_sel, axi_parents,
+		0x0040, 0, 3, INVALID_MUX_GATE_BIT /* 7 */),
+	MUX(TOP_MEM_SEL, mem_sel, mem_parents,
+		0x0040, 8, 1, INVALID_MUX_GATE_BIT /* 15 */),
+	MUX(TOP_DDRPHYCFG_SEL, ddrphycfg_sel, ddrphycfg_parents,
+		0x0040, 16, 1, 23),
+	MUX(TOP_MM_SEL, mm_sel, mm_parents, 0x0040, 24, 4, 31),
+	/* CLK_CFG_1 */
+	MUX(TOP_PWM_SEL, pwm_sel, pwm_parents, 0x0050, 0, 2, 7),
+	MUX(TOP_VDEC_SEL, vdec_sel, vdec_parents, 0x0050, 8, 4, 15),
+	MUX(TOP_VENC_SEL, venc_sel, venc_parents, 0x0050, 16, 4, 23),
+	MUX(TOP_MFG_SEL, mfg_sel, mfg_parents, 0x0050, 24, 4, 31),
+	/* CLK_CFG_2 */
+	MUX(TOP_CAMTG_SEL, camtg_sel, camtg_parents, 0x0060, 0, 3, 7),
+	MUX(TOP_UART_SEL, uart_sel, uart_parents, 0x0060, 8, 1, 15),
+	MUX(TOP_SPI_SEL, spi_sel, spi_parents, 0x0060, 16, 3, 23),
+	MUX(TOP_USB20_SEL, usb20_sel, usb20_parents, 0x0060, 24, 2, 31),
+	/* CLK_CFG_3 */
+	MUX(TOP_USB30_SEL, usb30_sel, usb30_parents, 0x0070, 0, 2, 7),
+	MUX(TOP_MSDC50_0_H_SEL, msdc50_0_h_sel, msdc50_0_h_parents,
+		0x0070, 8, 3, 15),
+	MUX(TOP_MSDC50_0_SEL, msdc50_0_sel, msdc50_0_parents,
+		0x0070, 16, 4, 23),
+	MUX(TOP_MSDC30_1_SEL, msdc30_1_sel, msdc30_1_parents,
+		0x0070, 24, 3, 31),
+	/* CLK_CFG_4 */
+	MUX(TOP_MSDC30_2_SEL, msdc30_2_sel, msdc30_2_parents, 0x0080, 0, 3, 7),
+	MUX(TOP_MSDC30_3_SEL, msdc30_3_sel, msdc30_3_parents, 0x0080, 8, 4, 15),
+	MUX(TOP_AUDIO_SEL, audio_sel, audio_parents, 0x0080, 16, 2, 23),
+	MUX(TOP_AUD_INTBUS_SEL, aud_intbus_sel, aud_intbus_parents,
+		0x0080, 24, 3, 31),
+	/* CLK_CFG_5 */
+	MUX(TOP_PMICSPI_SEL, pmicspi_sel, pmicspi_parents,
+		0x0090, 0, 3, 7 /* 7:5 */),
+	MUX(TOP_SCP_SEL, scp_sel, scp_parents, 0x0090, 8, 3, 15),
+	MUX(TOP_ATB_SEL, atb_sel, atb_parents, 0x0090, 16, 2, 23),
+	MUX(TOP_VENC_LT_SEL, venclt_sel, venc_lt_parents, 0x0090, 24, 4, 31),
+	/* CLK_CFG_6 */
+	MUX(TOP_DPI0_SEL, dpi0_sel, dpi0_parents, 0x00a0, 0, 3, 7),
+	MUX(TOP_IRDA_SEL, irda_sel, irda_parents, 0x00a0, 8, 2, 15),
+	MUX(TOP_CCI400_SEL, cci400_sel, cci400_parents, 0x00a0, 16, 3, 23),
+	MUX(TOP_AUD_1_SEL, aud_1_sel, aud_1_parents, 0x00a0, 24, 2, 31),
+	/* CLK_CFG_7 */
+	MUX(TOP_AUD_2_SEL, aud_2_sel, aud_2_parents, 0x00b0, 0, 2, 7),
+	MUX(TOP_MEM_MFG_IN_SEL, mem_mfg_in_sel, mem_mfg_in_parents,
+		0x00b0, 8, 2, 15),
+	MUX(TOP_AXI_MFG_IN_SEL, axi_mfg_in_sel, axi_mfg_in_parents,
+		0x00b0, 16, 2, 23),
+	MUX(TOP_SCAM_SEL, scam_sel, scam_parents, 0x00b0, 24, 2, 31),
+	/* CLK_CFG_12 */
+	MUX(TOP_SPINFI_IFR_SEL, spinfi_ifr_sel, spinfi_ifr_parents,
+		0x00c0, 0, 3, 7),
+	MUX(TOP_HDMI_SEL, hdmi_sel, hdmi_parents, 0x00c0, 8, 2, 15),
+	MUX(TOP_DPILVDS_SEL, dpilvds_sel, dpilvds_parents, 0x00c0, 24, 3, 31),
+	/* CLK_CFG_13 */
+	MUX(TOP_MSDC50_2_H_SEL, msdc50_2_h_sel, msdc50_2_h_parents,
+		0x00d0, 0, 3, 7),
+	MUX(TOP_HDCP_SEL, hdcp_sel, hdcp_parents, 0x00d0, 8, 2, 15),
+	MUX(TOP_HDCP_24M_SEL, hdcp_24m_sel, hdcp_24m_parents,
+		0x00d0, 16, 2, 23),
+	MUX(TOP_RTC_SEL, rtc_sel, rtc_parents,
+		0x00d0, 24, 2, INVALID_MUX_GATE_BIT /* 31 */),
+};
+
+static void __init mtk_init_clk_topckgen(void __iomem *top_base,
+		struct clk_onecell_data *clk_data)
+{
+	int i;
+	struct clk *clk;
+
+	for (i = 0; i < ARRAY_SIZE(top_muxes); i++) {
+		struct mtk_mux *mux = &top_muxes[i];
+
+		clk = mtk_clk_register_mux(mux->name,
+			mux->parent_names, mux->num_parents,
+			top_base + mux->reg, mux->shift, mux->width,
+			mux->gate, &lock);
+
+		if (IS_ERR(clk)) {
+			pr_err("Failed to register clk %s: %ld\n",
+					mux->name, PTR_ERR(clk));
+			continue;
+		}
+
+		if (clk_data)
+			clk_data->clks[mux->id] = clk;
+	}
+}
+
+static struct mtk_pll plls[] __initdata = {
+	PLL(APMIXED_ARMCA15PLL, armca15pll, clk26m, 0x0200, 0x020c, 0x00000001,
+		HAVE_PLL_HP, &mt8173_arm_pll_ops),
+	PLL(APMIXED_ARMCA7PLL, armca7pll, clk26m, 0x0210, 0x021c, 0x00000001,
+		HAVE_PLL_HP, &mt8173_arm_pll_ops),
+	PLL(APMIXED_MAINPLL, mainpll, clk26m, 0x0220, 0x022c, 0xf0000101,
+		HAVE_PLL_HP | HAVE_RST_BAR, &mt8173_sdm_pll_ops),
+	PLL(APMIXED_UNIVPLL, univpll, clk26m, 0x0230, 0x023c, 0xfe000001,
+		HAVE_RST_BAR | HAVE_FIX_FRQ | PLL_AO, &mt8173_univ_pll_ops),
+	PLL(APMIXED_MMPLL, mmpll, clk26m, 0x0240, 0x024c, 0x00000001,
+		HAVE_PLL_HP, &mt8173_mm_pll_ops),
+	PLL(APMIXED_MSDCPLL, msdcpll, clk26m, 0x0250, 0x025c, 0x00000001,
+		HAVE_PLL_HP, &mt8173_sdm_pll_ops),
+	PLL(APMIXED_VENCPLL, vencpll, clk26m, 0x0260, 0x026c, 0x00000001,
+		HAVE_PLL_HP, &mt8173_sdm_pll_ops),
+	PLL(APMIXED_TVDPLL, tvdpll, clk26m, 0x0270, 0x027c, 0x00000001,
+		HAVE_PLL_HP, &mt8173_sdm_pll_ops),
+	PLL(APMIXED_MPLL, mpll, clk26m, 0x0280, 0x028c, 0x00000001,
+		HAVE_PLL_HP, &mt8173_sdm_pll_ops),
+	PLL(APMIXED_VCODECPLL, vcodecpll, clk26m, 0x0290, 0x029c, 0x00000001,
+		HAVE_PLL_HP, &mt8173_sdm_pll_ops),
+	PLL(APMIXED_APLL1, apll1, clk26m, 0x02a0, 0x02b0, 0x00000001,
+		HAVE_PLL_HP, &mt8173_aud_pll_ops),
+	PLL(APMIXED_APLL2, apll2, clk26m, 0x02b4, 0x02c4, 0x00000001,
+		HAVE_PLL_HP, &mt8173_aud_pll_ops),
+	PLL(APMIXED_LVDSPLL, lvdspll, clk26m, 0x02d0, 0x02dc, 0x00000001,
+		HAVE_PLL_HP, &mt8173_sdm_pll_ops),
+	PLL(APMIXED_MSDCPLL2, msdcpll2, clk26m, 0x02f0, 0x02fc, 0x00000001,
+		HAVE_PLL_HP, &mt8173_sdm_pll_ops),
+};
+
+static void __init mtk_init_clk_apmixedsys(void __iomem *apmixed_base,
+		struct clk_onecell_data *clk_data)
+{
+	int i;
+	struct clk *clk;
+
+	for (i = 0; i < ARRAY_SIZE(plls); i++) {
+		struct mtk_pll *pll = &plls[i];
+
+		clk = mtk_clk_register_pll(pll->name, pll->parent_name,
+				apmixed_base + pll->reg,
+				apmixed_base + pll->pwr_reg,
+				pll->en_mask, pll->flags, pll->ops, &lock);
+
+		if (IS_ERR(clk)) {
+			pr_err("Failed to register clk %s: %ld\n",
+					pll->name, PTR_ERR(clk));
+			continue;
+		}
+
+		if (clk_data)
+			clk_data->clks[pll->id] = clk;
+	}
+}
+
+static struct mtk_gate_regs infra_cg_regs = {
+	.set_ofs = 0x0040,
+	.clr_ofs = 0x0044,
+	.sta_ofs = 0x0048,
+};
+
+static struct mtk_gate infra_clks[] __initdata = {
+	GATE(INFRA_DBGCLK, infra_dbgclk, axi_sel, infra_cg_regs,
+		0, &mtk_clk_gate_ops_setclr),
+	GATE(INFRA_SMI, infra_smi, mm_sel, infra_cg_regs,
+		1, &mtk_clk_gate_ops_setclr),
+	GATE(INFRA_AUDIO, infra_audio, aud_intbus_sel, infra_cg_regs,
+		5, &mtk_clk_gate_ops_setclr),
+	GATE(INFRA_GCE, infra_gce, axi_sel, infra_cg_regs,
+		6, &mtk_clk_gate_ops_setclr),
+	GATE(INFRA_L2C_SRAM, infra_l2c_sram, axi_sel, infra_cg_regs,
+		7, &mtk_clk_gate_ops_setclr),
+	GATE(INFRA_M4U, infra_m4u, mem_sel, infra_cg_regs,
+		8, &mtk_clk_gate_ops_setclr),
+	GATE(INFRA_CPUM, infra_cpum, clk_null, infra_cg_regs,
+		15, &mtk_clk_gate_ops_setclr),
+	GATE(INFRA_KP, infra_kp, axi_sel, infra_cg_regs,
+		16, &mtk_clk_gate_ops_setclr),
+	GATE(INFRA_CEC, infra_cec, clk26m, infra_cg_regs,
+		18, &mtk_clk_gate_ops_setclr),
+	GATE(INFRA_PMICSPI, infra_pmicspi, pmicspi_sel, infra_cg_regs,
+		22, &mtk_clk_gate_ops_setclr),
+	GATE(INFRA_PMICWRAP, infra_pmicwrap, axi_sel, infra_cg_regs,
+		23, &mtk_clk_gate_ops_setclr),
+};
+
+static struct mtk_gate_regs peri0_cg_regs = {
+	.set_ofs = 0x0008,
+	.clr_ofs = 0x0010,
+	.sta_ofs = 0x0018,
+};
+
+static struct mtk_gate_regs peri1_cg_regs = {
+	.set_ofs = 0x000c,
+	.clr_ofs = 0x0014,
+	.sta_ofs = 0x001c,
+};
+
+static struct mtk_gate peri_clks[] __initdata = {
+	/* PERI0 */
+	GATE(PERI_NFI, peri_nfi, axi_sel, peri0_cg_regs,
+		0, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_THERM, peri_therm, axi_sel, peri0_cg_regs,
+		1, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_PWM1, peri_pwm1, axi_sel, peri0_cg_regs,
+		2, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_PWM2, peri_pwm2, axi_sel, peri0_cg_regs,
+		3, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_PWM3, peri_pwm3, axi_sel, peri0_cg_regs,
+		4, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_PWM4, peri_pwm4, axi_sel, peri0_cg_regs,
+		5, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_PWM5, peri_pwm5, axi_sel, peri0_cg_regs,
+		6, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_PWM6, peri_pwm6, axi_sel, peri0_cg_regs,
+		7, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_PWM7, peri_pwm7, axi_sel, peri0_cg_regs,
+		8, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_PWM, peri_pwm, axi_sel, peri0_cg_regs,
+		9, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_USB0, peri_usb0, usb20_sel, peri0_cg_regs,
+		10, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_USB1, peri_usb1, usb20_sel, peri0_cg_regs,
+		11, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_AP_DMA, peri_ap_dma, axi_sel, peri0_cg_regs,
+		12, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_MSDC30_0, peri_msdc30_0, msdc50_0_sel, peri0_cg_regs,
+		13, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_MSDC30_1, peri_msdc30_1, msdc30_1_sel, peri0_cg_regs,
+		14, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_MSDC30_2, peri_msdc30_2, msdc30_2_sel, peri0_cg_regs,
+		15, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_MSDC30_3, peri_msdc30_3, msdc30_3_sel, peri0_cg_regs,
+		16, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_NLI_ARB, peri_nli_arb, axi_sel, peri0_cg_regs,
+		17, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_IRDA, peri_irda, irda_sel, peri0_cg_regs,
+		18, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_UART0, peri_uart0, uart_sel, peri0_cg_regs,
+		19, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_UART1, peri_uart1, uart_sel, peri0_cg_regs,
+		20, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_UART2, peri_uart2, uart_sel, peri0_cg_regs,
+		21, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_UART3, peri_uart3, uart_sel, peri0_cg_regs,
+		22, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_I2C0, peri_i2c0, axi_sel, peri0_cg_regs,
+		23, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_I2C1, peri_i2c1, axi_sel, peri0_cg_regs,
+		24, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_I2C2, peri_i2c2, axi_sel, peri0_cg_regs,
+		25, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_I2C3, peri_i2c3, axi_sel, peri0_cg_regs,
+		26, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_I2C4, peri_i2c4, axi_sel, peri0_cg_regs,
+		27, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_AUXADC, peri_auxadc, clk26m, peri0_cg_regs,
+		28, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_SPI0, peri_spi0, spi_sel, peri0_cg_regs,
+		29, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_I2C5, peri_i2c5, axi_sel, peri0_cg_regs,
+		30, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_NFIECC, peri_nfiecc, axi_sel, peri0_cg_regs,
+		31, &mtk_clk_gate_ops_setclr),
+	/* PERI1 */
+	GATE(PERI_SPI, peri_spi, spi_sel, peri1_cg_regs,
+		0, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_IRRX, peri_irrx, spi_sel, peri1_cg_regs,
+		1, &mtk_clk_gate_ops_setclr),
+	GATE(PERI_I2C6, peri_i2c6, axi_sel, peri1_cg_regs,
+		2, &mtk_clk_gate_ops_setclr),
+};
+
+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(TOP_NR_CLK);
+
+	mtk_init_factors(root_clk_alias, ARRAY_SIZE(root_clk_alias), clk_data);
+	mtk_init_factors(top_divs, ARRAY_SIZE(top_divs), clk_data);
+	mtk_init_clk_topckgen(base, 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);
+}
+CLK_OF_DECLARE(mtk_topckgen, "mediatek,mt8173-topckgen", mtk_topckgen_init);
+
+static void __init mtk_apmixedsys_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(APMIXED_NR_CLK);
+
+	mtk_init_clk_apmixedsys(base, 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);
+}
+CLK_OF_DECLARE(mtk_apmixedsys, "mediatek,mt8173-apmixedsys",
+		mtk_apmixedsys_init);
+
+static void __init mtk_infrasys_init(struct device_node *node)
+{
+	struct clk_onecell_data *clk_data;
+	struct regmap *regmap;
+	int r;
+
+	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;
+	}
+
+	clk_data = mtk_alloc_clk_data(INFRA_NR_CLK);
+
+	mtk_init_clk_gates(regmap, 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;
+	struct regmap *regmap;
+	int r;
+
+	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;
+	}
+
+	clk_data = mtk_alloc_clk_data(PERI_NR_CLK);
+
+	mtk_init_clk_gates(regmap, peri_clks, ARRAY_SIZE(peri_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, 0);
+}
+CLK_OF_DECLARE(mtk_pericfg, "mediatek,mt8173-pericfg", mtk_pericfg_init);
-- 
2.1.4


^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH 07/13] dt: bindings: Add MediaTek MT8135/MT8173 reset controller defines
  2015-02-09 10:47 [PATCH v5]: clk: Add common clock support for Mediatek MT8135 and MT8173 Sascha Hauer
                   ` (5 preceding siblings ...)
  2015-02-09 10:47 ` [PATCH 06/13] clk: mediatek: Add basic clocks for Mediatek MT8173 Sascha Hauer
@ 2015-02-09 10:47 ` Sascha Hauer
  2015-02-09 10:47 ` [PATCH 08/13] soc: mediatek: Add PMIC wrapper for MT8135 and MT6397 SoC Sascha Hauer
                   ` (5 subsequent siblings)
  12 siblings, 0 replies; 27+ messages in thread
From: Sascha Hauer @ 2015-02-09 10:47 UTC (permalink / raw)
  To: Matthias Brugger
  Cc: linux-arm-kernel, linux-kernel, Rob Herring, Eddie Huang,
	Lee Jones, Yingjoe Chen (陳英洲),
	Henry Chen, YH Chen (陳昱豪),
	kernel, Mike Turquette, Sascha Hauer

This adds the reset defines for the MT8135/MT8173 pericfg and infracfg
controllers. Needed for device trees to specify the reset numbers in
pericfg / infracfg reset consumers

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 .../dt-bindings/reset-controller/mt8135-resets.h   | 64 ++++++++++++++++++++++
 .../dt-bindings/reset-controller/mt8173-resets.h   | 63 +++++++++++++++++++++
 2 files changed, 127 insertions(+)
 create mode 100644 include/dt-bindings/reset-controller/mt8135-resets.h
 create mode 100644 include/dt-bindings/reset-controller/mt8173-resets.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 */
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 */
-- 
2.1.4


^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH 08/13] soc: mediatek: Add PMIC wrapper for MT8135 and MT6397 SoC
  2015-02-09 10:47 [PATCH v5]: clk: Add common clock support for Mediatek MT8135 and MT8173 Sascha Hauer
                   ` (6 preceding siblings ...)
  2015-02-09 10:47 ` [PATCH 07/13] dt: bindings: Add MediaTek MT8135/MT8173 reset controller defines Sascha Hauer
@ 2015-02-09 10:47 ` Sascha Hauer
  2015-02-09 10:47 ` [PATCH 09/13] ARM: dts: mediatek: Enable clock support for Mediatek MT8135 Sascha Hauer
                   ` (4 subsequent siblings)
  12 siblings, 0 replies; 27+ messages in thread
From: Sascha Hauer @ 2015-02-09 10:47 UTC (permalink / raw)
  To: Matthias Brugger
  Cc: linux-arm-kernel, linux-kernel, Rob Herring, Eddie Huang,
	Lee Jones, Yingjoe Chen (陳英洲),
	Henry Chen, YH Chen (陳昱豪),
	kernel, Mike Turquette, Flora Fu, Sascha Hauer

From: Flora Fu <flora.fu@mediatek.com>

This adds support for the PMIC wrapper found on MediaTek MT8135 and
MT8173 SoCs.

On MediaTek MT8135, MT8173 and other SoCs the PMIC is connected via
SPI. The SPI master interface is not directly visible to the CPU, but
only through the PMIC wrapper inside the SoC. The communication between
the SoC and the PMIC can optionally be encrypted. Also a non standard
Dual IO SPI mode can be used to increase speed. The MT8135 also supports
a special feature named "IP Pairing". With IP Pairing the pins of some
SoC internal peripherals can be on the PMIC. The signals of these pins
are routed over the SPI bus using the pwrap bridge. Because of these
optional non SPI conform features the PMIC driver is not implemented as
a SPI bus master driver.

Signed-off-by: Flora Fu, MediaTek
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 .../devicetree/bindings/soc/mediatek/pwrap.txt     |   56 ++
 drivers/soc/mediatek/Kconfig                       |   11 +
 drivers/soc/mediatek/Makefile                      |    1 +
 drivers/soc/mediatek/mtk-pmic-wrap.c               | 1027 ++++++++++++++++++++
 4 files changed, 1095 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/soc/mediatek/pwrap.txt
 create mode 100644 drivers/soc/mediatek/Kconfig
 create mode 100644 drivers/soc/mediatek/Makefile
 create mode 100644 drivers/soc/mediatek/mtk-pmic-wrap.c

diff --git a/Documentation/devicetree/bindings/soc/mediatek/pwrap.txt b/Documentation/devicetree/bindings/soc/mediatek/pwrap.txt
new file mode 100644
index 0000000..66cc528
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/mediatek/pwrap.txt
@@ -0,0 +1,56 @@
+MediaTek PMIC Wrapper Driver
+
+This document describes the binding for the MediaTek PMIC wrapper.
+
+On MediaTek MT8135, MT8173 and other SoCs the PMIC is connected via
+SPI. The SPI master interface is not directly visible to the CPU, but
+only through the PMIC wrapper inside the SoC. The communication between
+the SoC and the PMIC can optionally be encrypted. Also a non standard
+Dual IO SPI mode can be used to increase speed.
+
+IP Pairing
+
+on MT8135 the pins of some SoC internal peripherals can be on the PMIC.
+The signals of these pins are routed over the SPI bus using the pwrap
+bridge. In the binding description below the properties needed for bridging
+are marked with "IP Pairing". These are optional on SoCs which do not support
+IP Pairing
+
+Required properties in pwrap device node.
+- compatible: "mediatek,mt8135-pwrap" or "mediatek,mt8173-pwrap"
+- interrupts: IRQ for pwrap in SOC
+- reg-names: Must include the following entries:
+  "pwrap": Main registers base
+  "pwrap-bridge": bridge base (IP Pairing)
+- reg: Must contain an entry for each entry in reg-names.
+- reset-names: Must include the following entries:
+  "pwrap"
+  "pwrap-bridge" (IP Pairing)
+- resets: Must contain an entry for each entry in reset-names.
+- clock-names: Must include the following entries:
+  "spi": SPI bus clock
+  "wrap": Main module clock
+- clocks: Must contain an entry for each entry in clock-names.
+
+Optional properities:
+- pmic: Mediatek PMIC MFD is the child device of pwrap
+  See the following for child node definitions:
+  Documentation/devicetree/bindings/mfd/mt6397.txt
+
+Example:
+	pwrap: pwrap@1000f000 {
+		compatible = "mediatek,mt8135-pwrap";
+		reg = <0 0x1000f000 0 0x1000>,
+			<0 0x11017000 0 0x1000>;
+		reg-names = "pwrap", "pwrap-bridge";
+		interrupts = <GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>;
+		resets = <&infracfg MT8135_INFRA_PMIC_WRAP_RST>,
+				<&pericfg MT8135_PERI_PWRAP_BRIDGE_SW_RST>;
+		reset-names = "pwrap", "pwrap-bridge";
+		clocks = <&clk26m>, <&clk26m>;
+		clock-names = "spi", "wrap";
+
+		pmic {
+			compatible = "mediatek,mt6397";
+		};
+	};
diff --git a/drivers/soc/mediatek/Kconfig b/drivers/soc/mediatek/Kconfig
new file mode 100644
index 0000000..b91665a
--- /dev/null
+++ b/drivers/soc/mediatek/Kconfig
@@ -0,0 +1,11 @@
+#
+# MediaTek SoC drivers
+#
+config MTK_PMIC_WRAP
+	tristate "MediaTek PMIC Wrapper Support"
+	depends on ARCH_MEDIATEK
+	select REGMAP
+	help
+	  Say yes here to add support for MediaTek PMIC Wrapper found
+	  on the MT8135 and MT8173 SoCs. The PMIC wrapper is a proprietary
+	  hardware to connect the PMIC.
diff --git a/drivers/soc/mediatek/Makefile b/drivers/soc/mediatek/Makefile
new file mode 100644
index 0000000..ecaf4de
--- /dev/null
+++ b/drivers/soc/mediatek/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_MTK_PMIC_WRAP) += mtk-pmic-wrap.o
diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c
new file mode 100644
index 0000000..bd1f881
--- /dev/null
+++ b/drivers/soc/mediatek/mtk-pmic-wrap.c
@@ -0,0 +1,1027 @@
+/*
+ * 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.
+ */
+#define DEBUG
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+
+#define PWRAP_MT8135_BRIDGE_IORD_ARB_EN		0x4
+#define PWRAP_MT8135_BRIDGE_WACS3_EN		0x10
+#define PWRAP_MT8135_BRIDGE_INIT_DONE3		0x14
+#define PWRAP_MT8135_BRIDGE_WACS4_EN		0x24
+#define PWRAP_MT8135_BRIDGE_INIT_DONE4		0x28
+#define PWRAP_MT8135_BRIDGE_INT_EN		0x38
+#define PWRAP_MT8135_BRIDGE_TIMER_EN		0x48
+#define PWRAP_MT8135_BRIDGE_WDT_UNIT		0x50
+#define PWRAP_MT8135_BRIDGE_WDT_SRC_EN		0x54
+
+/* macro for wrapper status */
+#define PWRAP_GET_WACS_RDATA(x)		(((x) >> 0) & 0x0000ffff)
+#define PWRAP_GET_WACS_FSM(x)		(((x) >> 16) & 0x00000007)
+#define PWRAP_GET_WACS_REQ(x)		(((x) >> 19) & 0x00000001)
+#define PWRAP_STATE_SYNC_IDLE0		(1 << 20)
+#define PWRAP_STATE_INIT_DONE0		(1 << 21)
+
+/* macro for WACS FSM */
+#define PWRAP_WACS_FSM_IDLE		0x00
+#define PWRAP_WACS_FSM_REQ		0x02
+#define PWRAP_WACS_FSM_WFDLE		0x04
+#define PWRAP_WACS_FSM_WFVLDCLR		0x06
+#define PWRAP_WACS_INIT_DONE		0x01
+#define PWRAP_WACS_WACS_SYNC_IDLE	0x01
+#define PWRAP_WACS_SYNC_BUSY		0x00
+
+/* macro for device wrapper default value */
+#define PWRAP_DEW_READ_TEST_VAL		0x5aa5
+#define PWRAP_DEW_WRITE_TEST_VAL	0xa55a
+
+/* macro for manual command */
+#define PWRAP_MAN_CMD_SPI_WRITE		(1 << 13)
+#define PWRAP_MAN_CMD_OP_CSH		(0x0 << 8)
+#define PWRAP_MAN_CMD_OP_CSL		(0x1 << 8)
+#define PWRAP_MAN_CMD_OP_CK		(0x2 << 8)
+#define PWRAP_MAN_CMD_OP_OUTS		(0x8 << 8)
+#define PWRAP_MAN_CMD_OP_OUTD		(0x9 << 8)
+#define PWRAP_MAN_CMD_OP_OUTQ		(0xa << 8)
+
+/* macro for slave device wrapper registers */
+#define PWRAP_DEW_BASE			0xbc00
+#define PWRAP_DEW_EVENT_OUT_EN		(PWRAP_DEW_BASE + 0x0)
+#define PWRAP_DEW_DIO_EN		(PWRAP_DEW_BASE + 0x2)
+#define PWRAP_DEW_EVENT_SRC_EN		(PWRAP_DEW_BASE + 0x4)
+#define PWRAP_DEW_EVENT_SRC		(PWRAP_DEW_BASE + 0x6)
+#define PWRAP_DEW_EVENT_FLAG		(PWRAP_DEW_BASE + 0x8)
+#define PWRAP_DEW_READ_TEST		(PWRAP_DEW_BASE + 0xa)
+#define PWRAP_DEW_WRITE_TEST		(PWRAP_DEW_BASE + 0xc)
+#define PWRAP_DEW_CRC_EN		(PWRAP_DEW_BASE + 0xe)
+#define PWRAP_DEW_CRC_VAL		(PWRAP_DEW_BASE + 0x10)
+#define PWRAP_DEW_MON_GRP_SEL		(PWRAP_DEW_BASE + 0x12)
+#define PWRAP_DEW_MON_FLAG_SEL		(PWRAP_DEW_BASE + 0x14)
+#define PWRAP_DEW_EVENT_TEST		(PWRAP_DEW_BASE + 0x16)
+#define PWRAP_DEW_CIPHER_KEY_SEL	(PWRAP_DEW_BASE + 0x18)
+#define PWRAP_DEW_CIPHER_IV_SEL		(PWRAP_DEW_BASE + 0x1a)
+#define PWRAP_DEW_CIPHER_LOAD		(PWRAP_DEW_BASE + 0x1c)
+#define PWRAP_DEW_CIPHER_START		(PWRAP_DEW_BASE + 0x1e)
+#define PWRAP_DEW_CIPHER_RDY		(PWRAP_DEW_BASE + 0x20)
+#define PWRAP_DEW_CIPHER_MODE		(PWRAP_DEW_BASE + 0x22)
+#define PWRAP_DEW_CIPHER_SWRST		(PWRAP_DEW_BASE + 0x24)
+#define PWRAP_MT8173_DEW_CIPHER_IV0	(PWRAP_DEW_BASE + 0x26)
+#define PWRAP_MT8173_DEW_CIPHER_IV1	(PWRAP_DEW_BASE + 0x28)
+#define PWRAP_MT8173_DEW_CIPHER_IV2	(PWRAP_DEW_BASE + 0x2a)
+#define PWRAP_MT8173_DEW_CIPHER_IV3	(PWRAP_DEW_BASE + 0x2c)
+#define PWRAP_MT8173_DEW_CIPHER_IV4	(PWRAP_DEW_BASE + 0x2e)
+#define PWRAP_MT8173_DEW_CIPHER_IV5	(PWRAP_DEW_BASE + 0x30)
+
+/*
+ * FIXME: These shouldn't be here. These registers are on the PMIC,
+ *        so they should be touched in the PMIC driver, not the driver
+ *        granting access to it.
+ */
+#define MT6397_WRP_CKPDN		0x011a
+#define MT6397_WRP_RST_CON		0x0120
+#define MT6397_TOP_CKCON2		0x012a
+#define MT6397_TOP_CKCON3		0x01d4
+
+enum pwrap_regs {
+	PWRAP_MUX_SEL,
+	PWRAP_WRAP_EN,
+	PWRAP_DIO_EN,
+	PWRAP_SIDLY,
+	PWRAP_CSHEXT_WRITE,
+	PWRAP_CSHEXT_READ,
+	PWRAP_CSLEXT_START,
+	PWRAP_CSLEXT_END,
+	PWRAP_STAUPD_PRD,
+	PWRAP_STAUPD_GRPEN,
+	PWRAP_STAUPD_MAN_TRIG,
+	PWRAP_STAUPD_STA,
+	PWRAP_WRAP_STA,
+	PWRAP_HARB_INIT,
+	PWRAP_HARB_HPRIO,
+	PWRAP_HIPRIO_ARB_EN,
+	PWRAP_HARB_STA0,
+	PWRAP_HARB_STA1,
+	PWRAP_MAN_EN,
+	PWRAP_MAN_CMD,
+	PWRAP_MAN_RDATA,
+	PWRAP_MAN_VLDCLR,
+	PWRAP_WACS0_EN,
+	PWRAP_INIT_DONE0,
+	PWRAP_WACS0_CMD,
+	PWRAP_WACS0_RDATA,
+	PWRAP_WACS0_VLDCLR,
+	PWRAP_WACS1_EN,
+	PWRAP_INIT_DONE1,
+	PWRAP_WACS1_CMD,
+	PWRAP_WACS1_RDATA,
+	PWRAP_WACS1_VLDCLR,
+	PWRAP_WACS2_EN,
+	PWRAP_INIT_DONE2,
+	PWRAP_WACS2_CMD,
+	PWRAP_WACS2_RDATA,
+	PWRAP_WACS2_VLDCLR,
+	PWRAP_INT_EN,
+	PWRAP_INT_FLG_RAW,
+	PWRAP_INT_FLG,
+	PWRAP_INT_CLR,
+	PWRAP_SIG_ADR,
+	PWRAP_SIG_MODE,
+	PWRAP_SIG_VALUE,
+	PWRAP_SIG_ERRVAL,
+	PWRAP_CRC_EN,
+	PWRAP_TIMER_EN,
+	PWRAP_TIMER_STA,
+	PWRAP_WDT_UNIT,
+	PWRAP_WDT_SRC_EN,
+	PWRAP_WDT_FLG,
+	PWRAP_DEBUG_INT_SEL,
+	PWRAP_CIPHER_KEY_SEL,
+	PWRAP_CIPHER_IV_SEL,
+	PWRAP_CIPHER_RDY,
+	PWRAP_CIPHER_MODE,
+	PWRAP_CIPHER_SWRST,
+	PWRAP_DCM_EN,
+	PWRAP_DCM_DBC_PRD,
+
+	/* MT8135 only regs */
+	PWRAP_CSHEXT,
+	PWRAP_EVENT_IN_EN,
+	PWRAP_EVENT_DST_EN,
+	PWRAP_RRARB_INIT,
+	PWRAP_RRARB_EN,
+	PWRAP_RRARB_STA0,
+	PWRAP_RRARB_STA1,
+	PWRAP_EVENT_STA,
+	PWRAP_EVENT_STACLR,
+	PWRAP_CIPHER_LOAD,
+	PWRAP_CIPHER_START,
+
+	/* MT8173 only regs */
+	PWRAP_RDDMY,
+	PWRAP_SI_CK_CON,
+	PWRAP_DVFS_ADR0,
+	PWRAP_DVFS_WDATA0,
+	PWRAP_DVFS_ADR1,
+	PWRAP_DVFS_WDATA1,
+	PWRAP_DVFS_ADR2,
+	PWRAP_DVFS_WDATA2,
+	PWRAP_DVFS_ADR3,
+	PWRAP_DVFS_WDATA3,
+	PWRAP_DVFS_ADR4,
+	PWRAP_DVFS_WDATA4,
+	PWRAP_DVFS_ADR5,
+	PWRAP_DVFS_WDATA5,
+	PWRAP_DVFS_ADR6,
+	PWRAP_DVFS_WDATA6,
+	PWRAP_DVFS_ADR7,
+	PWRAP_DVFS_WDATA7,
+	PWRAP_SPMINF_STA,
+	PWRAP_CIPHER_EN,
+};
+
+static int mt8173_regs[] = {
+	[PWRAP_MUX_SEL] =		0x0,
+	[PWRAP_WRAP_EN] =		0x4,
+	[PWRAP_DIO_EN] =		0x8,
+	[PWRAP_SIDLY] =			0xc,
+	[PWRAP_RDDMY] =			0x10,
+	[PWRAP_SI_CK_CON] =		0x14,
+	[PWRAP_CSHEXT_WRITE] =		0x18,
+	[PWRAP_CSHEXT_READ] =		0x1c,
+	[PWRAP_CSLEXT_START] =		0x20,
+	[PWRAP_CSLEXT_END] =		0x24,
+	[PWRAP_STAUPD_PRD] =		0x28,
+	[PWRAP_STAUPD_GRPEN] =		0x2c,
+	[PWRAP_STAUPD_MAN_TRIG] =	0x40,
+	[PWRAP_STAUPD_STA] =		0x44,
+	[PWRAP_WRAP_STA] =		0x48,
+	[PWRAP_HARB_INIT] =		0x4c,
+	[PWRAP_HARB_HPRIO] =		0x50,
+	[PWRAP_HIPRIO_ARB_EN] =		0x54,
+	[PWRAP_HARB_STA0] =		0x58,
+	[PWRAP_HARB_STA1] =		0x5c,
+	[PWRAP_MAN_EN] =		0x60,
+	[PWRAP_MAN_CMD] =		0x64,
+	[PWRAP_MAN_RDATA] =		0x68,
+	[PWRAP_MAN_VLDCLR] =		0x6c,
+	[PWRAP_WACS0_EN] =		0x70,
+	[PWRAP_INIT_DONE0] =		0x74,
+	[PWRAP_WACS0_CMD] =		0x78,
+	[PWRAP_WACS0_RDATA] =		0x7c,
+	[PWRAP_WACS0_VLDCLR] =		0x80,
+	[PWRAP_WACS1_EN] =		0x84,
+	[PWRAP_INIT_DONE1] =		0x88,
+	[PWRAP_WACS1_CMD] =		0x8c,
+	[PWRAP_WACS1_RDATA] =		0x90,
+	[PWRAP_WACS1_VLDCLR] =		0x94,
+	[PWRAP_WACS2_EN] =		0x98,
+	[PWRAP_INIT_DONE2] =		0x9c,
+	[PWRAP_WACS2_CMD] =		0xa0,
+	[PWRAP_WACS2_RDATA] =		0xa4,
+	[PWRAP_WACS2_VLDCLR] =		0xa8,
+	[PWRAP_INT_EN] =		0xac,
+	[PWRAP_INT_FLG_RAW] =		0xb0,
+	[PWRAP_INT_FLG] =		0xb4,
+	[PWRAP_INT_CLR] =		0xb8,
+	[PWRAP_SIG_ADR] =		0xbc,
+	[PWRAP_SIG_MODE] =		0xc0,
+	[PWRAP_SIG_VALUE] =		0xc4,
+	[PWRAP_SIG_ERRVAL] =		0xc8,
+	[PWRAP_CRC_EN] =		0xcc,
+	[PWRAP_TIMER_EN] =		0xd0,
+	[PWRAP_TIMER_STA] =		0xd4,
+	[PWRAP_WDT_UNIT] =		0xd8,
+	[PWRAP_WDT_SRC_EN] =		0xdc,
+	[PWRAP_WDT_FLG] =		0xe0,
+	[PWRAP_DEBUG_INT_SEL] =		0xe4,
+	[PWRAP_DVFS_ADR0] =		0xe8,
+	[PWRAP_DVFS_WDATA0] =		0xec,
+	[PWRAP_DVFS_ADR1] =		0xf0,
+	[PWRAP_DVFS_WDATA1] =		0xf4,
+	[PWRAP_DVFS_ADR2] =		0xf8,
+	[PWRAP_DVFS_WDATA2] =		0xfc,
+	[PWRAP_DVFS_ADR3] =		0x100,
+	[PWRAP_DVFS_WDATA3] =		0x104,
+	[PWRAP_DVFS_ADR4] =		0x108,
+	[PWRAP_DVFS_WDATA4] =		0x10c,
+	[PWRAP_DVFS_ADR5] =		0x110,
+	[PWRAP_DVFS_WDATA5] =		0x114,
+	[PWRAP_DVFS_ADR6] =		0x118,
+	[PWRAP_DVFS_WDATA6] =		0x11c,
+	[PWRAP_DVFS_ADR7] =		0x120,
+	[PWRAP_DVFS_WDATA7] =		0x124,
+	[PWRAP_SPMINF_STA] =		0x128,
+	[PWRAP_CIPHER_KEY_SEL] =	0x12c,
+	[PWRAP_CIPHER_IV_SEL] =		0x130,
+	[PWRAP_CIPHER_EN] =		0x134,
+	[PWRAP_CIPHER_RDY] =		0x138,
+	[PWRAP_CIPHER_MODE] =		0x13c,
+	[PWRAP_CIPHER_SWRST] =		0x140,
+	[PWRAP_DCM_EN] =		0x144,
+	[PWRAP_DCM_DBC_PRD] =		0x148,
+};
+
+static int mt8135_regs[] = {
+	[PWRAP_MUX_SEL] =		0x0,
+	[PWRAP_WRAP_EN] =		0x4,
+	[PWRAP_DIO_EN] =		0x8,
+	[PWRAP_SIDLY] =			0xc,
+	[PWRAP_CSHEXT] =		0x10,
+	[PWRAP_CSHEXT_WRITE] =		0x14,
+	[PWRAP_CSHEXT_READ] =		0x18,
+	[PWRAP_CSLEXT_START] =		0x1c,
+	[PWRAP_CSLEXT_END] =		0x20,
+	[PWRAP_STAUPD_PRD] =		0x24,
+	[PWRAP_STAUPD_GRPEN] =		0x28,
+	[PWRAP_STAUPD_MAN_TRIG] =	0x2c,
+	[PWRAP_STAUPD_STA] =		0x30,
+	[PWRAP_EVENT_IN_EN] =		0x34,
+	[PWRAP_EVENT_DST_EN] =		0x38,
+	[PWRAP_WRAP_STA] =		0x3c,
+	[PWRAP_RRARB_INIT] =		0x40,
+	[PWRAP_RRARB_EN] =		0x44,
+	[PWRAP_RRARB_STA0] =		0x48,
+	[PWRAP_RRARB_STA1] =		0x4c,
+	[PWRAP_HARB_INIT] =		0x50,
+	[PWRAP_HARB_HPRIO] =		0x54,
+	[PWRAP_HIPRIO_ARB_EN] =		0x58,
+	[PWRAP_HARB_STA0] =		0x5c,
+	[PWRAP_HARB_STA1] =		0x60,
+	[PWRAP_MAN_EN] =		0x64,
+	[PWRAP_MAN_CMD] =		0x68,
+	[PWRAP_MAN_RDATA] =		0x6c,
+	[PWRAP_MAN_VLDCLR] =		0x70,
+	[PWRAP_WACS0_EN] =		0x74,
+	[PWRAP_INIT_DONE0] =		0x78,
+	[PWRAP_WACS0_CMD] =		0x7c,
+	[PWRAP_WACS0_RDATA] =		0x80,
+	[PWRAP_WACS0_VLDCLR] =		0x84,
+	[PWRAP_WACS1_EN] =		0x88,
+	[PWRAP_INIT_DONE1] =		0x8c,
+	[PWRAP_WACS1_CMD] =		0x90,
+	[PWRAP_WACS1_RDATA] =		0x94,
+	[PWRAP_WACS1_VLDCLR] =		0x98,
+	[PWRAP_WACS2_EN] =		0x9c,
+	[PWRAP_INIT_DONE2] =		0xa0,
+	[PWRAP_WACS2_CMD] =		0xa4,
+	[PWRAP_WACS2_RDATA] =		0xa8,
+	[PWRAP_WACS2_VLDCLR] =		0xac,
+	[PWRAP_INT_EN] =		0xb0,
+	[PWRAP_INT_FLG_RAW] =		0xb4,
+	[PWRAP_INT_FLG] =		0xb8,
+	[PWRAP_INT_CLR] =		0xbc,
+	[PWRAP_SIG_ADR] =		0xc0,
+	[PWRAP_SIG_MODE] =		0xc4,
+	[PWRAP_SIG_VALUE] =		0xc8,
+	[PWRAP_SIG_ERRVAL] =		0xcc,
+	[PWRAP_CRC_EN] =		0xd0,
+	[PWRAP_EVENT_STA] =		0xd4,
+	[PWRAP_EVENT_STACLR] =		0xd8,
+	[PWRAP_TIMER_EN] =		0xdc,
+	[PWRAP_TIMER_STA] =		0xe0,
+	[PWRAP_WDT_UNIT] =		0xe4,
+	[PWRAP_WDT_SRC_EN] =		0xe8,
+	[PWRAP_WDT_FLG] =		0xec,
+	[PWRAP_DEBUG_INT_SEL] =		0xf0,
+	[PWRAP_CIPHER_KEY_SEL] =	0x134,
+	[PWRAP_CIPHER_IV_SEL] =		0x138,
+	[PWRAP_CIPHER_LOAD] =		0x13c,
+	[PWRAP_CIPHER_START] =		0x140,
+	[PWRAP_CIPHER_RDY] =		0x144,
+	[PWRAP_CIPHER_MODE] =		0x148,
+	[PWRAP_CIPHER_SWRST] =		0x14c,
+	[PWRAP_DCM_EN] =		0x15c,
+	[PWRAP_DCM_DBC_PRD] =		0x160,
+};
+
+enum pwrap_type {
+	PWRAP_MT8135,
+	PWRAP_MT8173,
+};
+
+struct pmic_wrapper_type {
+	int *regs;
+	enum pwrap_type type;
+	u32 arb_en_all;
+};
+
+static struct pmic_wrapper_type pwrap_mt8135 = {
+	.regs = mt8135_regs,
+	.type = PWRAP_MT8135,
+	.arb_en_all = 0x1ff,
+};
+
+static struct pmic_wrapper_type pwrap_mt8173 = {
+	.regs = mt8173_regs,
+	.type = PWRAP_MT8173,
+	.arb_en_all = 0x3f,
+};
+
+struct pmic_wrapper {
+	struct device *dev;
+	void __iomem *base;
+	struct regmap *regmap;
+	int *regs;
+	enum pwrap_type type;
+	u32 arb_en_all;
+	struct clk *clk_spi;
+	struct clk *clk_wrap;
+	struct reset_control *rstc;
+
+	struct reset_control *rstc_bridge;
+	void __iomem *bridge_base;
+};
+
+static inline int pwrap_is_mt8135(struct pmic_wrapper *wrp)
+{
+	return wrp->type == PWRAP_MT8135;
+}
+
+static inline int pwrap_is_mt8173(struct pmic_wrapper *wrp)
+{
+	return wrp->type == PWRAP_MT8173;
+}
+
+static u32 pwrap_readl(struct pmic_wrapper *wrp, enum pwrap_regs reg)
+{
+	return readl(wrp->base + wrp->regs[reg]);
+}
+
+static void pwrap_writel(struct pmic_wrapper *wrp, u32 val, enum pwrap_regs reg)
+{
+	writel(val, wrp->base + wrp->regs[reg]);
+}
+
+static bool pwrap_is_fsm_idle(struct pmic_wrapper *wrp)
+{
+	u32 val = pwrap_readl(wrp, PWRAP_WACS2_RDATA);
+
+	return PWRAP_GET_WACS_FSM(val) == PWRAP_WACS_FSM_IDLE;
+}
+
+static bool pwrap_is_fsm_vldclr(struct pmic_wrapper *wrp)
+{
+	u32 val = pwrap_readl(wrp, PWRAP_WACS2_RDATA);
+
+	return PWRAP_GET_WACS_FSM(val) == PWRAP_WACS_FSM_WFVLDCLR;
+}
+
+static bool pwrap_is_sync_idle(struct pmic_wrapper *wrp)
+{
+	return pwrap_readl(wrp, PWRAP_WACS2_RDATA) & PWRAP_STATE_SYNC_IDLE0;
+}
+
+static bool pwrap_is_fsm_idle_and_sync_idle(struct pmic_wrapper *wrp)
+{
+	u32 val = pwrap_readl(wrp, PWRAP_WACS2_RDATA);
+
+	return (PWRAP_GET_WACS_FSM(val) == PWRAP_WACS_FSM_IDLE) &&
+		(val & PWRAP_STATE_SYNC_IDLE0);
+}
+
+static int pwrap_wait_for_state(struct pmic_wrapper *wrp,
+		bool (*fp)(struct pmic_wrapper *))
+{
+	unsigned long timeout;
+
+	timeout = jiffies + usecs_to_jiffies(255);
+
+	do {
+		if (time_after(jiffies, timeout))
+			return fp(wrp) ? 0 : -ETIMEDOUT;
+		if (fp(wrp))
+			return 0;
+	} while (1);
+}
+
+static int pwrap_write(struct pmic_wrapper *wrp, u32 adr, u32 wdata)
+{
+	int ret;
+	u32 val;
+
+	val = pwrap_readl(wrp, PWRAP_WACS2_RDATA);
+	if (PWRAP_GET_WACS_FSM(val) == PWRAP_WACS_FSM_WFVLDCLR)
+		pwrap_writel(wrp, 1, PWRAP_WACS2_VLDCLR);
+
+	ret = pwrap_wait_for_state(wrp, pwrap_is_fsm_idle);
+	if (ret)
+		return ret;
+
+	pwrap_writel(wrp, (1 << 31) | ((adr >> 1) << 16) | wdata,
+			PWRAP_WACS2_CMD);
+
+	return 0;
+}
+
+static int pwrap_read(struct pmic_wrapper *wrp, u32 adr, u32 *rdata)
+{
+	int ret;
+	u32 val;
+
+	val = pwrap_readl(wrp, PWRAP_WACS2_RDATA);
+	if (PWRAP_GET_WACS_FSM(val) == PWRAP_WACS_FSM_WFVLDCLR)
+		pwrap_writel(wrp, 1, PWRAP_WACS2_VLDCLR);
+
+	ret = pwrap_wait_for_state(wrp, pwrap_is_fsm_idle);
+	if (ret)
+		return ret;
+
+	pwrap_writel(wrp, (adr >> 1) << 16, PWRAP_WACS2_CMD);
+
+	ret = pwrap_wait_for_state(wrp, pwrap_is_fsm_vldclr);
+	if (ret)
+		return ret;
+
+	*rdata = PWRAP_GET_WACS_RDATA(pwrap_readl(wrp, PWRAP_WACS2_RDATA));
+
+	return 0;
+}
+
+static int pwrap_regmap_read(void *context, u32 adr, u32 *rdata)
+{
+	return pwrap_read(context, adr, rdata);
+}
+
+static int pwrap_regmap_write(void *context, u32 adr, u32 wdata)
+{
+	return pwrap_write(context, adr, wdata);
+}
+
+static int pwrap_reset_spislave(struct pmic_wrapper *wrp)
+{
+	int ret, i;
+
+	pwrap_writel(wrp, 0, PWRAP_HIPRIO_ARB_EN);
+	pwrap_writel(wrp, 0, PWRAP_WRAP_EN);
+	pwrap_writel(wrp, 1, PWRAP_MUX_SEL);
+	pwrap_writel(wrp, 1, PWRAP_MAN_EN);
+	pwrap_writel(wrp, 0, PWRAP_DIO_EN);
+
+	pwrap_writel(wrp, PWRAP_MAN_CMD_SPI_WRITE | PWRAP_MAN_CMD_OP_CSL,
+			PWRAP_MAN_CMD);
+	pwrap_writel(wrp, PWRAP_MAN_CMD_SPI_WRITE | PWRAP_MAN_CMD_OP_OUTS,
+			PWRAP_MAN_CMD);
+	pwrap_writel(wrp, PWRAP_MAN_CMD_SPI_WRITE | PWRAP_MAN_CMD_OP_CSH,
+			PWRAP_MAN_CMD);
+
+	for (i = 0; i < 4; i++)
+		pwrap_writel(wrp, PWRAP_MAN_CMD_SPI_WRITE | PWRAP_MAN_CMD_OP_OUTS,
+				PWRAP_MAN_CMD);
+
+	ret = pwrap_wait_for_state(wrp, pwrap_is_sync_idle);
+	if (ret) {
+		dev_err(wrp->dev, "%s fail, ret=%d\n", __func__, ret);
+		return ret;
+	}
+
+	pwrap_writel(wrp, 0, PWRAP_MAN_EN);
+	pwrap_writel(wrp, 0, PWRAP_MUX_SEL);
+
+	return 0;
+}
+
+/*
+ * pwrap_init_sidly - configure serial input delay
+ *
+ * This configures the serial input delay. We can configure 0, 2, 4 or 6ns
+ * delay. Do a read test with all possible values and chose the best delay.
+ */
+static int pwrap_init_sidly(struct pmic_wrapper *wrp)
+{
+	u32 rdata;
+	u32 i;
+	u32 pass = 0;
+	signed char dly[16] = {
+		-1, 0, 1, 0, 2, -1, 1, 1, 3, -1, -1, -1, 3, -1, 2, 1
+	};
+
+	for (i = 0; i < 4; i++) {
+		pwrap_writel(wrp, i, PWRAP_SIDLY);
+		pwrap_read(wrp, PWRAP_DEW_READ_TEST, &rdata);
+		printk("%s: 0x%04x\n", __func__, rdata);
+		if (rdata == PWRAP_DEW_READ_TEST_VAL) {
+			dev_dbg(wrp->dev, "[Read Test] pass, SIDLY=%x\n", i);
+			pass |= 1 << i;
+		}
+	}
+
+	if (dly[pass] < 0) {
+		dev_err(wrp->dev, "sidly pass range 0x%x not continuous\n",
+				pass);
+		return -EIO;
+	}
+
+	pwrap_writel(wrp, dly[pass], PWRAP_SIDLY);
+
+	return 0;
+}
+
+static int pwrap_init_reg_clock(struct pmic_wrapper *wrp)
+{
+	u32 wdata;
+	u32 rdata;
+	unsigned long rate_spi;
+	int ck_mhz;
+
+	rate_spi = clk_get_rate(wrp->clk_spi);
+
+	if (rate_spi > 26000000)
+		ck_mhz = 26;
+	else if (rate_spi > 18)
+		ck_mhz = 18;
+	else
+		ck_mhz = 0;
+
+	pwrap_read(wrp, MT6397_TOP_CKCON2, &rdata);
+	wdata = rdata & ~(0x3 << 10);
+
+	if (ck_mhz == 18)
+		wdata |= 0x1 << 10;
+
+	if (pwrap_write(wrp, MT6397_TOP_CKCON2, wdata))  {
+		dev_err(wrp->dev, "Enable PMIC TOP_CKCON2 fail\n");
+		return -EFAULT;
+	}
+
+	switch (ck_mhz) {
+	case 18:
+		if (pwrap_is_mt8135(wrp))
+			pwrap_writel(wrp, 0xc, PWRAP_CSHEXT);
+		pwrap_writel(wrp, 0x4, PWRAP_CSHEXT_WRITE);
+		pwrap_writel(wrp, 0xc, PWRAP_CSHEXT_READ);
+		pwrap_writel(wrp, 0x0, PWRAP_CSLEXT_START);
+		pwrap_writel(wrp, 0x0, PWRAP_CSLEXT_END);
+		break;
+	case 26:
+		if (pwrap_is_mt8135(wrp))
+			pwrap_writel(wrp, 0x4, PWRAP_CSHEXT);
+		pwrap_writel(wrp, 0x0, PWRAP_CSHEXT_WRITE);
+		pwrap_writel(wrp, 0x4, PWRAP_CSHEXT_READ);
+		pwrap_writel(wrp, 0x0, PWRAP_CSLEXT_START);
+		pwrap_writel(wrp, 0x0, PWRAP_CSLEXT_END);
+		break;
+	case 0:
+		if (pwrap_is_mt8135(wrp))
+			pwrap_writel(wrp, 0xf, PWRAP_CSHEXT);
+		pwrap_writel(wrp, 0xf, PWRAP_CSHEXT_WRITE);
+		pwrap_writel(wrp, 0xf, PWRAP_CSHEXT_READ);
+		pwrap_writel(wrp, 0xf, PWRAP_CSLEXT_START);
+		pwrap_writel(wrp, 0xf, PWRAP_CSLEXT_END);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Enable PMIC side reg clock */
+	if (pwrap_write(wrp, MT6397_WRP_CKPDN, 0) ||
+			pwrap_write(wrp, MT6397_WRP_RST_CON, 0)) {
+		dev_err(wrp->dev, "Enable PMIC fail\n");
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+static bool pwrap_is_cipher_ready(struct pmic_wrapper *wrp)
+{
+	return pwrap_readl(wrp, PWRAP_CIPHER_RDY) & 1;
+}
+
+static bool pwrap_is_pmic_cipher_ready(struct pmic_wrapper *wrp)
+{
+	u32 rdata;
+	int ret;
+
+	ret = pwrap_read(wrp, PWRAP_DEW_CIPHER_RDY, &rdata);
+	if (ret)
+		return 0;
+
+	return rdata == 1;
+}
+
+static int pwrap_init_cipher(struct pmic_wrapper *wrp)
+{
+	int ret;
+	u32 rdata;
+
+	pwrap_writel(wrp, 0x1, PWRAP_CIPHER_SWRST);
+	pwrap_writel(wrp, 0x0, PWRAP_CIPHER_SWRST);
+	pwrap_writel(wrp, 0x1, PWRAP_CIPHER_KEY_SEL);
+	pwrap_writel(wrp, 0x2, PWRAP_CIPHER_IV_SEL);
+
+	if (pwrap_is_mt8135(wrp)) {
+		pwrap_writel(wrp, 1, PWRAP_CIPHER_LOAD);
+		pwrap_writel(wrp, 1, PWRAP_CIPHER_START);
+	} else {
+		pwrap_writel(wrp, 1, PWRAP_CIPHER_EN);
+	}
+
+	/* Config cipher mode @PMIC */
+	pwrap_write(wrp, PWRAP_DEW_CIPHER_SWRST, 0x1);
+	pwrap_write(wrp, PWRAP_DEW_CIPHER_SWRST, 0x0);
+	pwrap_write(wrp, PWRAP_DEW_CIPHER_KEY_SEL, 0x1);
+	pwrap_write(wrp, PWRAP_DEW_CIPHER_IV_SEL, 0x2);
+	pwrap_write(wrp, PWRAP_DEW_CIPHER_LOAD, 0x1);
+	pwrap_write(wrp, PWRAP_DEW_CIPHER_START, 0x1);
+
+	/* wait for cipher data ready@AP */
+	ret = pwrap_wait_for_state(wrp, pwrap_is_cipher_ready);
+	if (ret) {
+		dev_err(wrp->dev, "cipher data ready@AP fail, ret=%d\n", ret);
+		return ret;
+	}
+
+	/* wait for cipher data ready@PMIC */
+	ret = pwrap_wait_for_state(wrp, pwrap_is_pmic_cipher_ready);
+	if (ret) {
+		dev_err(wrp->dev, "timeout waiting for cipher data ready@PMIC\n");
+		return ret;
+	}
+
+	/* wait for cipher mode idle */
+	pwrap_write(wrp, PWRAP_DEW_CIPHER_MODE, 0x1);
+	ret = pwrap_wait_for_state(wrp, pwrap_is_fsm_idle_and_sync_idle);
+	if (ret) {
+		dev_err(wrp->dev, "cipher mode idle fail, ret=%d\n", ret);
+		return ret;
+	}
+
+	pwrap_writel(wrp, 1, PWRAP_CIPHER_MODE);
+
+	/* Write Test */
+	if (pwrap_write(wrp, PWRAP_DEW_WRITE_TEST, PWRAP_DEW_WRITE_TEST_VAL) ||
+	    pwrap_read(wrp, PWRAP_DEW_WRITE_TEST, &rdata) ||
+			(rdata != PWRAP_DEW_WRITE_TEST_VAL)) {
+		dev_err(wrp->dev, "rdata=0x%04X\n", rdata);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+static int pwrap_init(struct pmic_wrapper *wrp)
+{
+	int ret;
+	u32 rdata;
+
+	reset_control_reset(wrp->rstc);
+	if (wrp->rstc_bridge)
+		reset_control_reset(wrp->rstc_bridge);
+
+	if (pwrap_is_mt8173(wrp)) {
+		/* Enable DCM */
+		pwrap_writel(wrp, 3, PWRAP_DCM_EN);
+		pwrap_writel(wrp, 0, PWRAP_DCM_DBC_PRD);
+	}
+
+	/* Reset SPI slave */
+	ret = pwrap_reset_spislave(wrp);
+	if (ret)
+		return ret;
+
+	pwrap_writel(wrp, 1, PWRAP_WRAP_EN);
+
+	pwrap_writel(wrp, wrp->arb_en_all, PWRAP_HIPRIO_ARB_EN);
+
+	pwrap_writel(wrp, 1, PWRAP_WACS2_EN);
+
+	ret = pwrap_init_reg_clock(wrp);
+	if (ret)
+		return ret;
+
+	/* Setup serial input delay */
+	ret = pwrap_init_sidly(wrp);
+	if (ret)
+		return ret;
+
+	if (pwrap_is_mt8173(wrp)) {
+		/*
+		 * Enable PMIC
+		 * (May not be necessary, depending on S/W partition)
+		 * set dewrap clock bit and clear dewrap reset bit
+		 */
+		if (pwrap_write(wrp, MT6397_WRP_CKPDN, 0) ||
+			pwrap_write(wrp, MT6397_WRP_RST_CON, 0)) {
+			dev_err(wrp->dev, "Enable PMIC fail\n");
+			return -EFAULT;
+		}
+	}
+
+	/* Enable dual IO mode */
+	pwrap_write(wrp, PWRAP_DEW_DIO_EN, 1);
+
+	/* Check IDLE & INIT_DONE in advance */
+	ret = pwrap_wait_for_state(wrp, pwrap_is_fsm_idle_and_sync_idle);
+	if (ret) {
+		dev_err(wrp->dev, "%s fail, ret=%d\n", __func__, ret);
+		return ret;
+	}
+
+	pwrap_writel(wrp, 1, PWRAP_DIO_EN);
+
+	/* Read Test */
+	pwrap_read(wrp, PWRAP_DEW_READ_TEST, &rdata);
+	if (rdata != PWRAP_DEW_READ_TEST_VAL) {
+		dev_err(wrp->dev, "Read test failed after switch to DIO mode: 0x%04x != 0x%04x\n",
+				PWRAP_DEW_READ_TEST_VAL, rdata);
+		return -EFAULT;
+	}
+
+	/* Enable encryption */
+	ret = pwrap_init_cipher(wrp);
+	if (ret)
+		return ret;
+
+	/* Signature checking - using CRC */
+	if (pwrap_write(wrp, PWRAP_DEW_CRC_EN, 0x1))
+		return -EFAULT;
+
+	pwrap_writel(wrp, 0x1, PWRAP_CRC_EN);
+	pwrap_writel(wrp, 0x0, PWRAP_SIG_MODE);
+	pwrap_writel(wrp, PWRAP_DEW_CRC_VAL, PWRAP_SIG_ADR);
+	pwrap_writel(wrp, wrp->arb_en_all, PWRAP_HIPRIO_ARB_EN);
+
+	if (pwrap_is_mt8135(wrp))
+		pwrap_writel(wrp, 0x7, PWRAP_RRARB_EN);
+
+	pwrap_writel(wrp, 0x1, PWRAP_WACS0_EN);
+	pwrap_writel(wrp, 0x1, PWRAP_WACS1_EN);
+	pwrap_writel(wrp, 0x1, PWRAP_WACS2_EN);
+	pwrap_writel(wrp, 0x5, PWRAP_STAUPD_PRD);
+	pwrap_writel(wrp, 0xff, PWRAP_STAUPD_GRPEN);
+	pwrap_writel(wrp, 0xf, PWRAP_WDT_UNIT);
+	pwrap_writel(wrp, 0xffffffff, PWRAP_WDT_SRC_EN);
+	pwrap_writel(wrp, 0x1, PWRAP_TIMER_EN);
+	pwrap_writel(wrp, ~((1 << 31) | (1 << 1)), PWRAP_INT_EN);
+
+	/* switch event pin from usbdl mode to normal mode @ MT6397 */
+	if (pwrap_read(wrp, MT6397_TOP_CKCON3, &rdata) ||
+			pwrap_write(wrp, MT6397_TOP_CKCON3, (rdata & 0x0007))) {
+		dev_err(wrp->dev, "switch event pin fail\n");
+		return -EFAULT;
+	}
+
+	if (pwrap_is_mt8135(wrp)) {
+		/* enable pwrap events and pwrap bridge in AP side */
+		pwrap_writel(wrp, 0x1, PWRAP_EVENT_IN_EN);
+		pwrap_writel(wrp, 0xffff, PWRAP_EVENT_DST_EN);
+		writel(0x7f, wrp->bridge_base + PWRAP_MT8135_BRIDGE_IORD_ARB_EN);
+		writel(0x1, wrp->bridge_base + PWRAP_MT8135_BRIDGE_WACS3_EN);
+		writel(0x1, wrp->bridge_base + PWRAP_MT8135_BRIDGE_WACS4_EN);
+		writel(0x1, wrp->bridge_base + PWRAP_MT8135_BRIDGE_WDT_UNIT);
+		writel(0xffff, wrp->bridge_base + PWRAP_MT8135_BRIDGE_WDT_SRC_EN);
+		writel(0x1, wrp->bridge_base + PWRAP_MT8135_BRIDGE_TIMER_EN);
+		writel(0x7ff, wrp->bridge_base + PWRAP_MT8135_BRIDGE_INT_EN);
+
+		/* enable PMIC event out and sources */
+		if (pwrap_write(wrp, PWRAP_DEW_EVENT_OUT_EN, 0x1) ||
+				pwrap_write(wrp, PWRAP_DEW_EVENT_SRC_EN, 0xffff)) {
+			dev_err(wrp->dev, "enable dewrap fail\n");
+			return -EFAULT;
+		}
+	} else {
+		/* PMIC_DEWRAP enables */
+		if (pwrap_write(wrp, PWRAP_DEW_EVENT_OUT_EN, 0x1) ||
+				pwrap_write(wrp, PWRAP_DEW_EVENT_SRC_EN, 0xffff)) {
+			dev_err(wrp->dev, "enable dewrap fail\n");
+			return -EFAULT;
+		}
+	}
+
+	/* Setup the init done registers */
+	pwrap_writel(wrp, 1, PWRAP_INIT_DONE2);
+	pwrap_writel(wrp, 1, PWRAP_INIT_DONE0);
+	pwrap_writel(wrp, 1, PWRAP_INIT_DONE1);
+
+	if (pwrap_is_mt8135(wrp)) {
+		writel(1, wrp->bridge_base + PWRAP_MT8135_BRIDGE_INIT_DONE3);
+		writel(1, wrp->bridge_base + PWRAP_MT8135_BRIDGE_INIT_DONE4);
+	}
+
+	return 0;
+}
+
+static irqreturn_t pwrap_interrupt(int irqno, void *dev_id)
+{
+	u32 rdata;
+	struct pmic_wrapper *wrp = dev_id;
+
+	rdata = pwrap_readl(wrp, PWRAP_INT_FLG);
+
+	dev_err(wrp->dev, "unexpected interrupt int=0x%x\n", rdata);
+
+	pwrap_writel(wrp, 0xffffffff, PWRAP_INT_CLR);
+
+	return IRQ_HANDLED;
+}
+
+static const struct regmap_config pwrap_regmap_config = {
+	.reg_bits = 16,
+	.val_bits = 16,
+	.reg_stride = 2,
+	.reg_read = pwrap_regmap_read,
+	.reg_write = pwrap_regmap_write,
+	.max_register = 0xffff,
+};
+
+static struct of_device_id of_pwrap_match_tbl[] = {
+	{
+		.compatible = "mediatek,mt8135-pwrap",
+		.data = &pwrap_mt8135,
+	}, {
+		.compatible = "mediatek,mt8173-pwrap",
+		.data = &pwrap_mt8173,
+	}, {
+		/* sentinel */
+	}
+};
+MODULE_DEVICE_TABLE(of, of_pwrap_match_tbl);
+
+static int pwrap_probe(struct platform_device *pdev)
+{
+	int ret, irq;
+	struct pmic_wrapper *wrp;
+	struct device_node *np = pdev->dev.of_node;
+	const struct of_device_id *of_id =
+		of_match_device(of_pwrap_match_tbl, &pdev->dev);
+	const struct pmic_wrapper_type *type;
+	struct resource *res;
+
+	wrp = devm_kzalloc(&pdev->dev, sizeof(*wrp), GFP_KERNEL);
+	if (!wrp)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, wrp);
+
+	type = of_id->data;
+	wrp->regs = type->regs;
+	wrp->type = type->type;
+	wrp->arb_en_all = type->arb_en_all;
+	wrp->dev = &pdev->dev;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pwrap");
+	wrp->base = devm_ioremap_resource(wrp->dev, res);
+	if (IS_ERR(wrp->base))
+		return PTR_ERR(wrp->base);
+
+	wrp->rstc = devm_reset_control_get(wrp->dev, "pwrap");
+	if (IS_ERR(wrp->rstc)) {
+		ret = PTR_ERR(wrp->rstc);
+		dev_dbg(wrp->dev, "cannot get pwrap reset: %d\n", ret);
+		return ret;
+	}
+
+	if (pwrap_is_mt8135(wrp)) {
+		res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+				"pwrap-bridge");
+		wrp->bridge_base = devm_ioremap_resource(wrp->dev, res);
+		if (IS_ERR(wrp->bridge_base))
+			return PTR_ERR(wrp->bridge_base);
+
+		wrp->rstc_bridge = devm_reset_control_get(wrp->dev, "pwrap-bridge");
+		if (IS_ERR(wrp->rstc_bridge)) {
+			ret = PTR_ERR(wrp->rstc_bridge);
+			dev_dbg(wrp->dev, "cannot get pwrap-bridge reset: %d\n", ret);
+			return ret;
+		}
+	}
+
+	wrp->clk_spi = devm_clk_get(wrp->dev, "spi");
+	if (IS_ERR(wrp->clk_spi)) {
+		dev_dbg(wrp->dev, "failed to get clock: %ld\n", PTR_ERR(wrp->clk_spi));
+		return PTR_ERR(wrp->clk_spi);
+	}
+
+	wrp->clk_wrap = devm_clk_get(wrp->dev, "wrap");
+	if (IS_ERR(wrp->clk_wrap)) {
+		dev_dbg(wrp->dev, "failed to get clock: %ld\n", PTR_ERR(wrp->clk_wrap));
+		return PTR_ERR(wrp->clk_wrap);
+	}
+
+	ret = clk_prepare_enable(wrp->clk_spi);
+	if (ret)
+		return ret;
+
+	ret = clk_prepare_enable(wrp->clk_wrap);
+	if (ret)
+		goto err_out1;
+
+	/* Enable internal dynamic clock */
+	pwrap_writel(wrp, 1, PWRAP_DCM_EN);
+	pwrap_writel(wrp, 0, PWRAP_DCM_DBC_PRD);
+
+	/*
+	 * The PMIC could already be initialized by the bootloader.
+	 * Skip initialization here in this case.
+	 */
+	if (!pwrap_readl(wrp, PWRAP_INIT_DONE2)) {
+		ret = pwrap_init(wrp);
+		if (ret) {
+			dev_dbg(wrp->dev, "init failed with %d\n", ret);
+			goto err_out2;
+		}
+	}
+
+	if (!(pwrap_readl(wrp, PWRAP_WACS2_RDATA) & PWRAP_STATE_INIT_DONE0)) {
+		dev_dbg(wrp->dev, "initialization isn't finished\n");
+		return -ENODEV;
+	}
+
+	irq = platform_get_irq(pdev, 0);
+	ret = devm_request_irq(wrp->dev, irq, pwrap_interrupt, IRQF_TRIGGER_HIGH,
+			"mt-pmic-pwrap", wrp);
+	if (ret)
+		goto err_out2;
+
+	wrp->regmap = devm_regmap_init(wrp->dev, NULL, wrp, &pwrap_regmap_config);
+	if (IS_ERR(wrp->regmap))
+		return PTR_ERR(wrp->regmap);
+
+	ret = of_platform_populate(np, NULL, NULL, wrp->dev);
+	if (ret) {
+		dev_dbg(wrp->dev, "failed to create child devices at %s\n",
+				np->full_name);
+		goto err_out2;
+	}
+
+	return 0;
+
+err_out2:
+	clk_disable_unprepare(wrp->clk_wrap);
+err_out1:
+	clk_disable_unprepare(wrp->clk_spi);
+
+	return ret;
+}
+
+static struct platform_driver pwrap_drv = {
+	.driver = {
+		.name = "mt-pmic-pwrap",
+		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(of_pwrap_match_tbl),
+	},
+	.probe = pwrap_probe,
+};
+
+module_platform_driver(pwrap_drv);
+
+MODULE_AUTHOR("Flora Fu, MediaTek");
+MODULE_DESCRIPTION("MediaTek MT8135 PMIC Wrapper Driver");
+MODULE_LICENSE("GPL");
-- 
2.1.4


^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH 09/13] ARM: dts: mediatek: Enable clock support for Mediatek MT8135.
  2015-02-09 10:47 [PATCH v5]: clk: Add common clock support for Mediatek MT8135 and MT8173 Sascha Hauer
                   ` (7 preceding siblings ...)
  2015-02-09 10:47 ` [PATCH 08/13] soc: mediatek: Add PMIC wrapper for MT8135 and MT6397 SoC Sascha Hauer
@ 2015-02-09 10:47 ` Sascha Hauer
  2015-02-09 10:51   ` Russell King - ARM Linux
  2015-02-09 10:47 ` [PATCH 10/13] ARM: dts: mt8135: Add pmic wrapper nodes Sascha Hauer
                   ` (3 subsequent siblings)
  12 siblings, 1 reply; 27+ messages in thread
From: Sascha Hauer @ 2015-02-09 10:47 UTC (permalink / raw)
  To: Matthias Brugger
  Cc: linux-arm-kernel, linux-kernel, Rob Herring, Eddie Huang,
	Lee Jones, Yingjoe Chen (陳英洲),
	Henry Chen, YH Chen (陳昱豪),
	kernel, Mike Turquette, James Liao, Sascha Hauer

From: James Liao <jamesjj.liao@mediatek.com>

This patch adds MT8135 clock controllers into device tree.

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>
---
 arch/arm/boot/dts/mt8135.dtsi | 39 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 39 insertions(+)

diff --git a/arch/arm/boot/dts/mt8135.dtsi b/arch/arm/boot/dts/mt8135.dtsi
index 7d56a98..7cb5e84 100644
--- a/arch/arm/boot/dts/mt8135.dtsi
+++ b/arch/arm/boot/dts/mt8135.dtsi
@@ -12,6 +12,7 @@
  * GNU General Public License for more details.
  */
 
+#include <dt-bindings/clock/mt8135-clk.h>
 #include <dt-bindings/interrupt-controller/irq.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 #include "skeleton64.dtsi"
@@ -86,6 +87,18 @@
 			clock-frequency = <32000>;
 			#clock-cells = <0>;
 		};
+
+		clk_null: clk_null {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-frequency = <0>;
+		};
+
+		clk26m: clk26m {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-frequency = <26000000>;
+		};
 	};
 
 	soc {
@@ -94,6 +107,26 @@
 		compatible = "simple-bus";
 		ranges;
 
+		topckgen: topckgen@10000000 {
+			compatible = "mediatek,mt8135-topckgen";
+			reg = <0 0x10000000 0 0x1000>;
+			#clock-cells = <1>;
+		};
+
+		infracfg: infracfg@10001000 {
+			#reset-cells = <1>;
+			#clock-cells = <1>;
+			compatible = "mediatek,mt8135-infracfg", "syscon";
+			reg = <0 0x10001000 0 0x1000>;
+		};
+
+		pericfg: pericfg@10003000 {
+			#reset-cells = <1>;
+			#clock-cells = <1>;
+			compatible = "mediatek,mt8135-pericfg", "syscon";
+			reg = <0 0x10003000 0 0x1000>;
+		};
+
 		timer: timer@10008000 {
 			compatible = "mediatek,mt8135-timer",
 					"mediatek,mt6577-timer";
@@ -103,6 +136,12 @@
 			clock-names = "system-clk", "rtc-clk";
 		};
 
+		apmixedsys: apmixedsys@10209000 {
+			compatible = "mediatek,mt8135-apmixedsys";
+			reg = <0 0x10209000 0 0x1000>;
+			#clock-cells = <1>;
+		};
+
 		gic: interrupt-controller@10211000 {
 			compatible = "arm,cortex-a15-gic";
 			interrupt-controller;
-- 
2.1.4


^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH 10/13] ARM: dts: mt8135: Add pmic wrapper nodes
  2015-02-09 10:47 [PATCH v5]: clk: Add common clock support for Mediatek MT8135 and MT8173 Sascha Hauer
                   ` (8 preceding siblings ...)
  2015-02-09 10:47 ` [PATCH 09/13] ARM: dts: mediatek: Enable clock support for Mediatek MT8135 Sascha Hauer
@ 2015-02-09 10:47 ` Sascha Hauer
  2015-02-09 10:47 ` [PATCH 11/13] ARM: dts: mt8135-evbp1: Add PMIC support Sascha Hauer
                   ` (2 subsequent siblings)
  12 siblings, 0 replies; 27+ messages in thread
From: Sascha Hauer @ 2015-02-09 10:47 UTC (permalink / raw)
  To: Matthias Brugger
  Cc: linux-arm-kernel, linux-kernel, Rob Herring, Eddie Huang,
	Lee Jones, Yingjoe Chen (陳英洲),
	Henry Chen, YH Chen (陳昱豪),
	kernel, Mike Turquette, Sascha Hauer

This adds the pmic wrapper node to the MediaTek MT8135 dtsi file.

This unit is used to access the PMIC on MediaTek boards.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 arch/arm/boot/dts/mt8135.dtsi | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/arch/arm/boot/dts/mt8135.dtsi b/arch/arm/boot/dts/mt8135.dtsi
index 7cb5e84..fb6d6db 100644
--- a/arch/arm/boot/dts/mt8135.dtsi
+++ b/arch/arm/boot/dts/mt8135.dtsi
@@ -15,6 +15,7 @@
 #include <dt-bindings/clock/mt8135-clk.h>
 #include <dt-bindings/interrupt-controller/irq.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/reset-controller/mt8135-resets.h>
 #include "skeleton64.dtsi"
 
 / {
@@ -127,6 +128,19 @@
 			reg = <0 0x10003000 0 0x1000>;
 		};
 
+		pwrap: pwrap@1000f000 {
+			compatible = "mediatek,mt8135-pwrap";
+			reg = <0 0x1000f000 0 0x1000>,
+				<0 0x11017000 0 0x1000>;
+			reg-names = "pwrap-base", "pwrap-bridge-base";
+			interrupts = <GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>;
+			resets = <&infracfg MT8135_INFRA_PMIC_WRAP_RST>,
+					<&pericfg MT8135_PERI_PWRAP_BRIDGE_SW_RST>;
+			reset-names = "pwrap", "pwrap-bridge";
+			clocks = <&clk26m>, <&clk26m>;
+			clock-names = "spi", "wrap";
+		};
+
 		timer: timer@10008000 {
 			compatible = "mediatek,mt8135-timer",
 					"mediatek,mt6577-timer";
-- 
2.1.4


^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH 11/13] ARM: dts: mt8135-evbp1: Add PMIC support
  2015-02-09 10:47 [PATCH v5]: clk: Add common clock support for Mediatek MT8135 and MT8173 Sascha Hauer
                   ` (9 preceding siblings ...)
  2015-02-09 10:47 ` [PATCH 10/13] ARM: dts: mt8135: Add pmic wrapper nodes Sascha Hauer
@ 2015-02-09 10:47 ` Sascha Hauer
  2015-02-09 10:47 ` [PATCH 12/13] mfd: dt-bindings: Add bindings for the MediaTek MT6397 PMIC Sascha Hauer
  2015-02-09 10:47 ` [PATCH 13/13] mfd: Add support " Sascha Hauer
  12 siblings, 0 replies; 27+ messages in thread
From: Sascha Hauer @ 2015-02-09 10:47 UTC (permalink / raw)
  To: Matthias Brugger
  Cc: linux-arm-kernel, linux-kernel, Rob Herring, Eddie Huang,
	Lee Jones, Yingjoe Chen (陳英洲),
	Henry Chen, YH Chen (陳昱豪),
	kernel, Mike Turquette, Sascha Hauer

The MT8135 eval board contains a MT6397 PMIC. This adds the
corresponding device node to the dts file.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 arch/arm/boot/dts/mt8135-evbp1.dts | 193 +++++++++++++++++++++++++++++++++++++
 1 file changed, 193 insertions(+)

diff --git a/arch/arm/boot/dts/mt8135-evbp1.dts b/arch/arm/boot/dts/mt8135-evbp1.dts
index a5adf97..3be2c8b 100644
--- a/arch/arm/boot/dts/mt8135-evbp1.dts
+++ b/arch/arm/boot/dts/mt8135-evbp1.dts
@@ -23,3 +23,196 @@
 		reg = <0 0x80000000 0 0x40000000>;
 	};
 };
+
+&pwrap {
+	pmic: mt6397 {
+		compatible = "mediatek,mt6397";
+
+		mt6397regulator: mt6397regulator {
+			compatible = "mediatek,mt6397-regulator";
+
+			mt6397_vpca15_reg: buck_vpca15 {
+				regulator-compatible = "buck_vpca15";
+				regulator-name = "vpca15";
+				regulator-min-microvolt = < 850000>;
+				regulator-max-microvolt = <1350000>;
+				regulator-ramp-delay = <12500>;
+				regulator-always-on;
+			};
+
+			mt6397_vpca7_reg: buck_vpca7 {
+				regulator-compatible = "buck_vpca7";
+				regulator-name = "vpca7";
+				regulator-min-microvolt = < 850000>;
+				regulator-max-microvolt = <1350000>;
+				regulator-ramp-delay = <12500>;
+				regulator-always-on;
+			};
+
+			mt6397_vsramca15_reg: buck_vsramca15 {
+				regulator-compatible = "buck_vsramca15";
+				regulator-name = "vsramca15";
+				regulator-min-microvolt = < 850000>;
+				regulator-max-microvolt = <1350000>;
+				regulator-ramp-delay = <12500>;
+				regulator-always-on;
+			};
+
+			mt6397_vsramca7_reg: buck_vsramca7 {
+				regulator-compatible = "buck_vsramca7";
+				regulator-name = "vsramca7";
+				regulator-min-microvolt = < 850000>;
+				regulator-max-microvolt = <1350000>;
+				regulator-ramp-delay = <12500>;
+				regulator-always-on;
+			};
+
+			mt6397_vcore_reg: buck_vcore {
+				regulator-compatible = "buck_vcore";
+				regulator-name = "vcore";
+				regulator-min-microvolt = < 850000>;
+				regulator-max-microvolt = <1350000>;
+				regulator-ramp-delay = <12500>;
+				regulator-always-on;
+			};
+
+			mt6397_vgpu_reg: buck_vgpu {
+				regulator-compatible = "buck_vgpu";
+				regulator-name = "vgpu";
+				regulator-min-microvolt = < 700000>;
+				regulator-max-microvolt = <1350000>;
+				regulator-ramp-delay = <12500>;
+				regulator-enable-ramp-delay = <115>;
+			};
+
+			mt6397_vdrm_reg: buck_vdrm {
+				regulator-compatible = "buck_vdrm";
+				regulator-name = "vdrm";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1400000>;
+				regulator-ramp-delay = <12500>;
+				regulator-always-on;
+			};
+
+			mt6397_vio18_reg: buck_vio18 {
+				regulator-compatible = "buck_vio18";
+				regulator-name = "vio18";
+				regulator-min-microvolt = <1620000>;
+				regulator-max-microvolt = <1980000>;
+				regulator-ramp-delay = <12500>;
+				regulator-always-on;
+			};
+
+			mt6397_vtcxo_reg: ldo_vtcxo {
+				regulator-compatible = "ldo_vtcxo";
+				regulator-name = "vtcxo";
+				regulator-always-on;
+			};
+
+			mt6397_va28_reg: ldo_va28 {
+				regulator-compatible = "ldo_va28";
+				regulator-name = "va28";
+				regulator-always-on;
+			};
+
+			mt6397_vcama_reg: ldo_vcama {
+				regulator-compatible = "ldo_vcama";
+				regulator-name = "vcama";
+				regulator-min-microvolt = <1500000>;
+				regulator-max-microvolt = <2800000>;
+				regulator-enable-ramp-delay = <218>;
+			};
+
+			mt6397_vio28_reg: ldo_vio28 {
+				regulator-compatible = "ldo_vio28";
+				regulator-name = "vio28";
+				regulator-always-on;
+			};
+
+			mt6397_vusb_reg: ldo_vusb {
+				regulator-compatible = "ldo_vusb";
+				regulator-name = "vusb";
+			};
+
+			mt6397_vmc_reg: ldo_vmc {
+				regulator-compatible = "ldo_vmc";
+				regulator-name = "vmc";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-enable-ramp-delay = <218>;
+			};
+
+			mt6397_vmch_reg: ldo_vmch {
+				regulator-compatible = "ldo_vmch";
+				regulator-name = "vmch";
+				regulator-min-microvolt = <3000000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-enable-ramp-delay = <218>;
+			};
+
+			mt6397_vemc_3v3_reg: ldo_vemc3v3 {
+				regulator-compatible = "ldo_vemc3v3";
+				regulator-name = "vemc_3v3";
+				regulator-min-microvolt = <3000000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-enable-ramp-delay = <218>;
+			};
+
+			mt6397_vgp1_reg: ldo_vgp1 {
+				regulator-compatible = "ldo_vgp1";
+				regulator-name = "vcamd";
+				regulator-min-microvolt = <1220000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-enable-ramp-delay = <240>;
+			};
+
+			mt6397_vgp2_reg: ldo_vgp2 {
+				regulator-compatible = "ldo_vgp2";
+				regulator-name = "vcamio";
+				regulator-min-microvolt = <1000000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-enable-ramp-delay = <218>;
+			};
+
+			mt6397_vgp3_reg: ldo_vgp3 {
+				regulator-compatible = "ldo_vgp3";
+				regulator-name = "vcamaf";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-enable-ramp-delay = <218>;
+			};
+
+			mt6397_vgp4_reg: ldo_vgp4 {
+				regulator-compatible = "ldo_vgp4";
+				regulator-name = "vgp4";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-enable-ramp-delay = <218>;
+			};
+
+			mt6397_vgp5_reg: ldo_vgp5 {
+				regulator-compatible = "ldo_vgp5";
+				regulator-name = "vgp5";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <3000000>;
+				regulator-enable-ramp-delay = <218>;
+			};
+
+			mt6397_vgp6_reg: ldo_vgp6 {
+				regulator-compatible = "ldo_vgp6";
+				regulator-name = "vgp6";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-enable-ramp-delay = <218>;
+			};
+
+			mt6397_vibr_reg: ldo_vibr {
+				regulator-compatible = "ldo_vibr";
+				regulator-name = "vibr";
+				regulator-min-microvolt = <1300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-enable-ramp-delay = <218>;
+			};
+		};
+	};
+};
-- 
2.1.4


^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH 12/13] mfd: dt-bindings: Add bindings for the MediaTek MT6397 PMIC
  2015-02-09 10:47 [PATCH v5]: clk: Add common clock support for Mediatek MT8135 and MT8173 Sascha Hauer
                   ` (10 preceding siblings ...)
  2015-02-09 10:47 ` [PATCH 11/13] ARM: dts: mt8135-evbp1: Add PMIC support Sascha Hauer
@ 2015-02-09 10:47 ` Sascha Hauer
  2015-02-09 10:47 ` [PATCH 13/13] mfd: Add support " Sascha Hauer
  12 siblings, 0 replies; 27+ messages in thread
From: Sascha Hauer @ 2015-02-09 10:47 UTC (permalink / raw)
  To: Matthias Brugger
  Cc: linux-arm-kernel, linux-kernel, Rob Herring, Eddie Huang,
	Lee Jones, Yingjoe Chen (陳英洲),
	Henry Chen, YH Chen (陳昱豪),
	kernel, Mike Turquette, Sascha Hauer

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 Documentation/devicetree/bindings/mfd/mt6397.txt | 70 ++++++++++++++++++++++++
 1 file changed, 70 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mfd/mt6397.txt

diff --git a/Documentation/devicetree/bindings/mfd/mt6397.txt b/Documentation/devicetree/bindings/mfd/mt6397.txt
new file mode 100644
index 0000000..15043e6
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/mt6397.txt
@@ -0,0 +1,70 @@
+MediaTek MT6397 Multifunction Device Driver
+
+MT6397 is a multifunction device with the following sub modules:
+- Regulator
+- RTC
+- Audio codec
+- GPIO
+- Clock
+
+It is interfaced to host controller using SPI interface by a proprietary hardware
+called PMIC wrapper or pwrap. MT6397 MFD is a child device of pwrap.
+See the following for pwarp node definitions:
+Documentation/devicetree/bindings/soc/pwrap.txt
+
+This document describes the binding for MFD device and its sub module.
+
+Required properties:
+compatible: "mediatek,mt6397"
+
+Optional subnodes:
+
+- rtc
+	Required properties:
+		- compatible: "mediatek,mt6397-rtc"
+- regulators
+	Required properties:
+		- compatible: "mediatek,mt6397-regulator"
+	see Documentation/devicetree/bindings/regulator/mt6397-regulator.txt
+- codec
+	Required properties:
+		- compatible: "mediatek,mt6397-codec"
+- clk
+	Required properties:
+		- compatible: "mediatek,mt6397-clk"
+
+Example:
+	pwrap: pwrap@1000f000 {
+		compatible = "mediatek,mt8135-pwrap";
+
+		...
+
+		pmic {
+			compatible = "mediatek,mt6397";
+
+			codec: mt6397codec {
+				compatible = "mediatek,mt6397-codec";
+			};
+
+			regulators {
+				compatible = "mediatek,mt6397-regulator";
+
+				mt6397_vpca15_reg: buck_vpca15 {
+					regulator-compatible = "buck_vpca15";
+					regulator-name = "vpca15";
+					regulator-min-microvolt = <850000>;
+					regulator-max-microvolt = <1400000>;
+					regulator-ramp-delay = <12500>;
+					regulator-always-on;
+				};
+
+				mt6397_vgp4_reg: ldo_vgp4 {
+					regulator-compatible = "ldo_vgp4";
+					regulator-name = "vgp4";
+					regulator-min-microvolt = <1200000>;
+					regulator-max-microvolt = <3300000>;
+					regulator-enable-ramp-delay = <218>;
+				};
+			};
+		};
+	};
-- 
2.1.4


^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH 13/13] mfd: Add support for the MediaTek MT6397 PMIC
  2015-02-09 10:47 [PATCH v5]: clk: Add common clock support for Mediatek MT8135 and MT8173 Sascha Hauer
                   ` (11 preceding siblings ...)
  2015-02-09 10:47 ` [PATCH 12/13] mfd: dt-bindings: Add bindings for the MediaTek MT6397 PMIC Sascha Hauer
@ 2015-02-09 10:47 ` Sascha Hauer
  2015-02-16  9:56   ` Lee Jones
  12 siblings, 1 reply; 27+ messages in thread
From: Sascha Hauer @ 2015-02-09 10:47 UTC (permalink / raw)
  To: Matthias Brugger
  Cc: linux-arm-kernel, linux-kernel, Rob Herring, Eddie Huang,
	Lee Jones, Yingjoe Chen (陳英洲),
	Henry Chen, YH Chen (陳昱豪),
	kernel, Mike Turquette, Flora Fu, Sascha Hauer, Samuel Ortiz

From: Flora Fu <flora.fu@mediatek.com>

This adds support for the MediaTek MT6397 PMIC. This is a
multifunction device with the following sub modules:

- Regulator
- RTC
- Audio codec
- GPIO
- Clock

It is interfaced to the host controller using SPI interface by a proprietary
hardware called PMIC wrapper or pwrap. MT6397 MFD is a child device of the
pwrap.

Signed-off-by: Flora Fu, MediaTek
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Cc: Samuel Ortiz <sameo@linux.intel.com>
Cc: Lee Jones <lee.jones@linaro.org>
---
 drivers/mfd/Kconfig                  |  10 +
 drivers/mfd/Makefile                 |   1 +
 drivers/mfd/mt6397-core.c            | 223 +++++++++++++++++++++
 include/linux/mfd/mt6397/core.h      |  64 +++++++
 include/linux/mfd/mt6397/registers.h | 362 +++++++++++++++++++++++++++++++++++
 5 files changed, 660 insertions(+)
 create mode 100644 drivers/mfd/mt6397-core.c
 create mode 100644 include/linux/mfd/mt6397/core.h
 create mode 100644 include/linux/mfd/mt6397/registers.h

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 2e6b731..7782e95 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -489,6 +489,16 @@ config MFD_MAX8998
 	  additional drivers must be enabled in order to use the functionality
 	  of the device.
 
+config MFD_MT6397
+	tristate "MediaTek MT6397 PMIC Support"
+	select MFD_CORE
+	select IRQ_DOMAIN
+	help
+	  Say yes here to add support for MediaTek MT6397 PMIC. This is
+	  a Power Management IC. This driver provides common support for
+	  accessing the device; additional drivers must be enabled in order
+	  to use the functionality of the device.
+
 config MFD_MENF21BMC
 	tristate "MEN 14F021P00 Board Management Controller Support"
 	depends on I2C
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 53467e2..329d4ed 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -179,3 +179,4 @@ obj-$(CONFIG_MFD_DLN2)		+= dln2.o
 
 intel-soc-pmic-objs		:= intel_soc_pmic_core.o intel_soc_pmic_crc.o
 obj-$(CONFIG_INTEL_SOC_PMIC)	+= intel-soc-pmic.o
+obj-$(CONFIG_MFD_MT6397)	+= mt6397-core.o
diff --git a/drivers/mfd/mt6397-core.c b/drivers/mfd/mt6397-core.c
new file mode 100644
index 0000000..b61c4eb
--- /dev/null
+++ b/drivers/mfd/mt6397-core.c
@@ -0,0 +1,223 @@
+/*
+ * 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.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/regmap.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/mt6397/core.h>
+#include <linux/mfd/mt6397/registers.h>
+
+static const struct mfd_cell mt6397_devs[] = {
+	{
+		.name = "mt6397-rtc",
+		.of_compatible = "mediatek,mt6397-rtc",
+	}, {
+		.name = "mt6397-regulator",
+		.of_compatible = "mediatek,mt6397-regulator",
+	}, {
+		.name = "mt6397-codec",
+		.of_compatible = "mediatek,mt6397-codec",
+	}, {
+		.name = "mt6397-clk",
+		.of_compatible = "mediatek,mt6397-clk",
+	},
+};
+
+static void mt6397_irq_lock(struct irq_data *data)
+{
+	struct mt6397_chip *mt6397 = irq_get_chip_data(data->irq);
+
+	mutex_lock(&mt6397->irqlock);
+}
+
+static void mt6397_irq_sync_unlock(struct irq_data *data)
+{
+	struct mt6397_chip *mt6397 = irq_get_chip_data(data->irq);
+
+	regmap_write(mt6397->regmap, MT6397_INT_CON0, mt6397->irq_masks_cur[0]);
+	regmap_write(mt6397->regmap, MT6397_INT_CON1, mt6397->irq_masks_cur[1]);
+
+	mutex_unlock(&mt6397->irqlock);
+}
+
+static void mt6397_irq_disable(struct irq_data *data)
+{
+	struct mt6397_chip *mt6397 = irq_get_chip_data(data->irq);
+	int shift = data->hwirq & 0xf;
+	int reg = data->hwirq >> 4;
+
+	mt6397->irq_masks_cur[reg] &= ~BIT(shift);
+}
+
+static void mt6397_irq_enable(struct irq_data *data)
+{
+	struct mt6397_chip *mt6397 = irq_get_chip_data(data->irq);
+	int shift = data->hwirq & 0xf;
+	int reg = data->hwirq >> 4;
+
+	mt6397->irq_masks_cur[reg] |= BIT(shift);
+}
+
+static struct irq_chip mt6397_irq_chip = {
+	.name = "mt6397-irq",
+	.irq_bus_lock = mt6397_irq_lock,
+	.irq_bus_sync_unlock = mt6397_irq_sync_unlock,
+	.irq_enable = mt6397_irq_enable,
+	.irq_disable = mt6397_irq_disable,
+};
+
+static void mt6397_irq_handle_reg(struct mt6397_chip *mt6397, int reg,
+		int irqbase)
+{
+	unsigned int status;
+	int i, irq, ret;
+
+	ret = regmap_read(mt6397->regmap, reg, &status);
+	if (ret) {
+		dev_err(mt6397->dev, "Failed to read irq status: %d\n", ret);
+		return;
+	}
+
+	for (i = 0; i < 16; i++) {
+		if (status & BIT(i)) {
+			irq = irq_find_mapping(mt6397->irq_domain, irqbase + i);
+			if (irq)
+				handle_nested_irq(irq);
+		}
+	}
+
+	regmap_write(mt6397->regmap, reg, status);
+}
+
+static irqreturn_t mt6397_irq_thread(int irq, void *data)
+{
+	struct mt6397_chip *mt6397 = data;
+
+	mt6397_irq_handle_reg(mt6397, MT6397_INT_STATUS0, 0);
+	mt6397_irq_handle_reg(mt6397, MT6397_INT_STATUS1, 16);
+
+	return IRQ_HANDLED;
+}
+
+static int mt6397_irq_domain_map(struct irq_domain *d, unsigned int irq,
+					irq_hw_number_t hw)
+{
+	struct mt6397_chip *mt6397 = d->host_data;
+
+	irq_set_chip_data(irq, mt6397);
+	irq_set_chip_and_handler(irq, &mt6397_irq_chip, handle_level_irq);
+	irq_set_nested_thread(irq, 1);
+	set_irq_flags(irq, IRQF_VALID);
+
+	return 0;
+}
+
+static struct irq_domain_ops mt6397_irq_domain_ops = {
+	.map = mt6397_irq_domain_map,
+};
+
+static int mt6397_irq_init(struct mt6397_chip *mt6397)
+{
+	int ret;
+
+	mutex_init(&mt6397->irqlock);
+
+	/* Mask all interrupt sources */
+	regmap_write(mt6397->regmap, MT6397_INT_CON0, 0x0);
+	regmap_write(mt6397->regmap, MT6397_INT_CON1, 0x0);
+
+	mt6397->irq_domain = irq_domain_add_linear(mt6397->dev->of_node,
+		MT6397_IRQ_NR, &mt6397_irq_domain_ops, mt6397);
+	if (!mt6397->irq_domain) {
+		dev_err(mt6397->dev, "could not create irq domain\n");
+		return -ENOMEM;
+	}
+
+	ret = devm_request_threaded_irq(mt6397->dev, mt6397->irq, NULL,
+		mt6397_irq_thread, IRQF_ONESHOT, "mt6397-pmic", mt6397);
+	if (ret) {
+		dev_err(mt6397->dev, "failed to register irq=%d; err: %d\n",
+			mt6397->irq, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int mt6397_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct mt6397_chip *mt6397;
+
+	mt6397 = devm_kzalloc(&pdev->dev, sizeof(*mt6397), GFP_KERNEL);
+	if (!mt6397)
+		return -ENOMEM;
+
+	mt6397->dev = &pdev->dev;
+	/*
+	 * mt6397 MFD is child device of soc pmic wrapper.
+	 * Regmap is set from its parent.
+	 */
+	mt6397->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+	if (!mt6397->regmap)
+		return -ENODEV;
+
+	platform_set_drvdata(pdev, mt6397);
+
+	mt6397->irq = platform_get_irq(pdev, 0);
+	if (mt6397->irq > 0) {
+		ret = mt6397_irq_init(mt6397);
+		if (ret)
+			return ret;
+	}
+
+	ret = mfd_add_devices(&pdev->dev, -1, mt6397_devs,
+			ARRAY_SIZE(mt6397_devs), NULL, 0, NULL);
+	if (ret)
+		dev_err(&pdev->dev, "failed to add child devices: %d\n", ret);
+
+	return ret;
+}
+
+static int mt6397_remove(struct platform_device *pdev)
+{
+	mfd_remove_devices(&pdev->dev);
+
+	return 0;
+}
+
+static const struct of_device_id mt6397_of_match[] = {
+	{ .compatible = "mediatek,mt6397" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, mt6397_of_match);
+
+static struct platform_driver mt6397_driver = {
+	.probe = mt6397_probe,
+	.remove = mt6397_remove,
+	.driver = {
+		.name = "mt6397",
+		.of_match_table = of_match_ptr(mt6397_of_match),
+	},
+};
+
+module_platform_driver(mt6397_driver);
+
+MODULE_AUTHOR("Flora Fu, MediaTek");
+MODULE_DESCRIPTION("Driver for MediaTek MT6397 PMIC");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:mt6397");
diff --git a/include/linux/mfd/mt6397/core.h b/include/linux/mfd/mt6397/core.h
new file mode 100644
index 0000000..cf5265b
--- /dev/null
+++ b/include/linux/mfd/mt6397/core.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 __MFD_MT6397_CORE_H__
+#define __MFD_MT6397_CORE_H__
+
+enum mt6397_irq_numbers {
+	MT6397_IRQ_SPKL_AB = 0,
+	MT6397_IRQ_SPKR_AB,
+	MT6397_IRQ_SPKL,
+	MT6397_IRQ_SPKR,
+	MT6397_IRQ_BAT_L,
+	MT6397_IRQ_BAT_H,
+	MT6397_IRQ_FG_BAT_L,
+	MT6397_IRQ_FG_BAT_H,
+	MT6397_IRQ_WATCHDOG,
+	MT6397_IRQ_PWRKEY,
+	MT6397_IRQ_THR_L,
+	MT6397_IRQ_THR_H,
+	MT6397_IRQ_VBATON_UNDET,
+	MT6397_IRQ_BVALID_DET,
+	MT6397_IRQ_CHRDET,
+	MT6397_IRQ_OV,
+	MT6397_IRQ_LDO,
+	MT6397_IRQ_HOMEKEY,
+	MT6397_IRQ_ACCDET,
+	MT6397_IRQ_AUDIO,
+	MT6397_IRQ_RTC,
+	MT6397_IRQ_PWRKEY_RSTB,
+	MT6397_IRQ_HDMI_SIFM,
+	MT6397_IRQ_HDMI_CEC,
+	MT6397_IRQ_VCA15,
+	MT6397_IRQ_VSRMCA15,
+	MT6397_IRQ_VCORE,
+	MT6397_IRQ_VGPU,
+	MT6397_IRQ_VIO18,
+	MT6397_IRQ_VPCA7,
+	MT6397_IRQ_VSRMCA7,
+	MT6397_IRQ_VDRM,
+	MT6397_IRQ_NR,
+};
+
+struct mt6397_chip {
+	struct device *dev;
+	struct regmap *regmap;
+	int irq;
+	struct irq_domain *irq_domain;
+	struct mutex irqlock;
+	u16 irq_masks_cur[2];
+	u16 irq_masks_cache[2];
+};
+
+#endif /* __MFD_MT6397_CORE_H__ */
diff --git a/include/linux/mfd/mt6397/registers.h b/include/linux/mfd/mt6397/registers.h
new file mode 100644
index 0000000..f23a0a6
--- /dev/null
+++ b/include/linux/mfd/mt6397/registers.h
@@ -0,0 +1,362 @@
+/*
+ * 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 __MFD_MT6397_REGISTERS_H__
+#define __MFD_MT6397_REGISTERS_H__
+
+/* PMIC Registers */
+#define MT6397_CID			0x0100
+#define MT6397_TOP_CKPDN		0x0102
+#define MT6397_TOP_CKPDN_SET		0x0104
+#define MT6397_TOP_CKPDN_CLR		0x0106
+#define MT6397_TOP_CKPDN2		0x0108
+#define MT6397_TOP_CKPDN2_SET		0x010A
+#define MT6397_TOP_CKPDN2_CLR		0x010C
+#define MT6397_TOP_GPIO_CKPDN		0x010E
+#define MT6397_TOP_RST_CON		0x0114
+#define MT6397_WRP_CKPDN		0x011A
+#define MT6397_WRP_RST_CON		0x0120
+#define MT6397_TOP_RST_MISC		0x0126
+#define MT6397_TOP_CKCON1		0x0128
+#define MT6397_TOP_CKCON2		0x012A
+#define MT6397_TOP_CKTST1		0x012C
+#define MT6397_TOP_CKTST2		0x012E
+#define MT6397_OC_DEG_EN		0x0130
+#define MT6397_OC_CTL0			0x0132
+#define MT6397_OC_CTL1			0x0134
+#define MT6397_OC_CTL2			0x0136
+#define MT6397_INT_RSV			0x0138
+#define MT6397_TEST_CON0		0x013A
+#define MT6397_TEST_CON1		0x013C
+#define MT6397_STATUS0			0x013E
+#define MT6397_STATUS1			0x0140
+#define MT6397_PGSTATUS			0x0142
+#define MT6397_CHRSTATUS		0x0144
+#define MT6397_OCSTATUS0		0x0146
+#define MT6397_OCSTATUS1		0x0148
+#define MT6397_OCSTATUS2		0x014A
+#define MT6397_HDMI_PAD_IE		0x014C
+#define MT6397_TEST_OUT_L		0x014E
+#define MT6397_TEST_OUT_H		0x0150
+#define MT6397_TDSEL_CON		0x0152
+#define MT6397_RDSEL_CON		0x0154
+#define MT6397_GPIO_SMT_CON0		0x0156
+#define MT6397_GPIO_SMT_CON1		0x0158
+#define MT6397_GPIO_SMT_CON2		0x015A
+#define MT6397_GPIO_SMT_CON3		0x015C
+#define MT6397_DRV_CON0			0x015E
+#define MT6397_DRV_CON1			0x0160
+#define MT6397_DRV_CON2			0x0162
+#define MT6397_DRV_CON3			0x0164
+#define MT6397_DRV_CON4			0x0166
+#define MT6397_DRV_CON5			0x0168
+#define MT6397_DRV_CON6			0x016A
+#define MT6397_DRV_CON7			0x016C
+#define MT6397_DRV_CON8			0x016E
+#define MT6397_DRV_CON9			0x0170
+#define MT6397_DRV_CON10		0x0172
+#define MT6397_DRV_CON11		0x0174
+#define MT6397_DRV_CON12		0x0176
+#define MT6397_INT_CON0			0x0178
+#define MT6397_INT_CON1			0x017E
+#define MT6397_INT_STATUS0		0x0184
+#define MT6397_INT_STATUS1		0x0186
+#define MT6397_FQMTR_CON0		0x0188
+#define MT6397_FQMTR_CON1		0x018A
+#define MT6397_FQMTR_CON2		0x018C
+#define MT6397_EFUSE_DOUT_0_15		0x01C4
+#define MT6397_EFUSE_DOUT_16_31		0x01C6
+#define MT6397_EFUSE_DOUT_32_47		0x01C8
+#define MT6397_EFUSE_DOUT_48_63		0x01CA
+#define MT6397_SPI_CON			0x01CC
+#define MT6397_TOP_CKPDN3		0x01CE
+#define MT6397_TOP_CKCON3		0x01D4
+#define MT6397_EFUSE_DOUT_64_79		0x01D6
+#define MT6397_EFUSE_DOUT_80_95		0x01D8
+#define MT6397_EFUSE_DOUT_96_111	0x01DA
+#define MT6397_EFUSE_DOUT_112_127	0x01DC
+#define MT6397_EFUSE_DOUT_128_143	0x01DE
+#define MT6397_EFUSE_DOUT_144_159	0x01E0
+#define MT6397_EFUSE_DOUT_160_175	0x01E2
+#define MT6397_EFUSE_DOUT_176_191	0x01E4
+#define MT6397_EFUSE_DOUT_192_207	0x01E6
+#define MT6397_EFUSE_DOUT_208_223	0x01E8
+#define MT6397_EFUSE_DOUT_224_239	0x01EA
+#define MT6397_EFUSE_DOUT_240_255	0x01EC
+#define MT6397_EFUSE_DOUT_256_271	0x01EE
+#define MT6397_EFUSE_DOUT_272_287	0x01F0
+#define MT6397_EFUSE_DOUT_288_300	0x01F2
+#define MT6397_EFUSE_DOUT_304_319	0x01F4
+#define MT6397_BUCK_CON0		0x0200
+#define MT6397_BUCK_CON1		0x0202
+#define MT6397_BUCK_CON2		0x0204
+#define MT6397_BUCK_CON3		0x0206
+#define MT6397_BUCK_CON4		0x0208
+#define MT6397_BUCK_CON5		0x020A
+#define MT6397_BUCK_CON6		0x020C
+#define MT6397_BUCK_CON7		0x020E
+#define MT6397_BUCK_CON8		0x0210
+#define MT6397_BUCK_CON9		0x0212
+#define MT6397_VCA15_CON0		0x0214
+#define MT6397_VCA15_CON1		0x0216
+#define MT6397_VCA15_CON2		0x0218
+#define MT6397_VCA15_CON3		0x021A
+#define MT6397_VCA15_CON4		0x021C
+#define MT6397_VCA15_CON5		0x021E
+#define MT6397_VCA15_CON6		0x0220
+#define MT6397_VCA15_CON7		0x0222
+#define MT6397_VCA15_CON8		0x0224
+#define MT6397_VCA15_CON9		0x0226
+#define MT6397_VCA15_CON10		0x0228
+#define MT6397_VCA15_CON11		0x022A
+#define MT6397_VCA15_CON12		0x022C
+#define MT6397_VCA15_CON13		0x022E
+#define MT6397_VCA15_CON14		0x0230
+#define MT6397_VCA15_CON15		0x0232
+#define MT6397_VCA15_CON16		0x0234
+#define MT6397_VCA15_CON17		0x0236
+#define MT6397_VCA15_CON18		0x0238
+#define MT6397_VSRMCA15_CON0		0x023A
+#define MT6397_VSRMCA15_CON1		0x023C
+#define MT6397_VSRMCA15_CON2		0x023E
+#define MT6397_VSRMCA15_CON3		0x0240
+#define MT6397_VSRMCA15_CON4		0x0242
+#define MT6397_VSRMCA15_CON5		0x0244
+#define MT6397_VSRMCA15_CON6		0x0246
+#define MT6397_VSRMCA15_CON7		0x0248
+#define MT6397_VSRMCA15_CON8		0x024A
+#define MT6397_VSRMCA15_CON9		0x024C
+#define MT6397_VSRMCA15_CON10		0x024E
+#define MT6397_VSRMCA15_CON11		0x0250
+#define MT6397_VSRMCA15_CON12		0x0252
+#define MT6397_VSRMCA15_CON13		0x0254
+#define MT6397_VSRMCA15_CON14		0x0256
+#define MT6397_VSRMCA15_CON15		0x0258
+#define MT6397_VSRMCA15_CON16		0x025A
+#define MT6397_VSRMCA15_CON17		0x025C
+#define MT6397_VSRMCA15_CON18		0x025E
+#define MT6397_VSRMCA15_CON19		0x0260
+#define MT6397_VSRMCA15_CON20		0x0262
+#define MT6397_VSRMCA15_CON21		0x0264
+#define MT6397_VCORE_CON0		0x0266
+#define MT6397_VCORE_CON1		0x0268
+#define MT6397_VCORE_CON2		0x026A
+#define MT6397_VCORE_CON3		0x026C
+#define MT6397_VCORE_CON4		0x026E
+#define MT6397_VCORE_CON5		0x0270
+#define MT6397_VCORE_CON6		0x0272
+#define MT6397_VCORE_CON7		0x0274
+#define MT6397_VCORE_CON8		0x0276
+#define MT6397_VCORE_CON9		0x0278
+#define MT6397_VCORE_CON10		0x027A
+#define MT6397_VCORE_CON11		0x027C
+#define MT6397_VCORE_CON12		0x027E
+#define MT6397_VCORE_CON13		0x0280
+#define MT6397_VCORE_CON14		0x0282
+#define MT6397_VCORE_CON15		0x0284
+#define MT6397_VCORE_CON16		0x0286
+#define MT6397_VCORE_CON17		0x0288
+#define MT6397_VCORE_CON18		0x028A
+#define MT6397_VGPU_CON0		0x028C
+#define MT6397_VGPU_CON1		0x028E
+#define MT6397_VGPU_CON2		0x0290
+#define MT6397_VGPU_CON3		0x0292
+#define MT6397_VGPU_CON4		0x0294
+#define MT6397_VGPU_CON5		0x0296
+#define MT6397_VGPU_CON6		0x0298
+#define MT6397_VGPU_CON7		0x029A
+#define MT6397_VGPU_CON8		0x029C
+#define MT6397_VGPU_CON9		0x029E
+#define MT6397_VGPU_CON10		0x02A0
+#define MT6397_VGPU_CON11		0x02A2
+#define MT6397_VGPU_CON12		0x02A4
+#define MT6397_VGPU_CON13		0x02A6
+#define MT6397_VGPU_CON14		0x02A8
+#define MT6397_VGPU_CON15		0x02AA
+#define MT6397_VGPU_CON16		0x02AC
+#define MT6397_VGPU_CON17		0x02AE
+#define MT6397_VGPU_CON18		0x02B0
+#define MT6397_VIO18_CON0		0x0300
+#define MT6397_VIO18_CON1		0x0302
+#define MT6397_VIO18_CON2		0x0304
+#define MT6397_VIO18_CON3		0x0306
+#define MT6397_VIO18_CON4		0x0308
+#define MT6397_VIO18_CON5		0x030A
+#define MT6397_VIO18_CON6		0x030C
+#define MT6397_VIO18_CON7		0x030E
+#define MT6397_VIO18_CON8		0x0310
+#define MT6397_VIO18_CON9		0x0312
+#define MT6397_VIO18_CON10		0x0314
+#define MT6397_VIO18_CON11		0x0316
+#define MT6397_VIO18_CON12		0x0318
+#define MT6397_VIO18_CON13		0x031A
+#define MT6397_VIO18_CON14		0x031C
+#define MT6397_VIO18_CON15		0x031E
+#define MT6397_VIO18_CON16		0x0320
+#define MT6397_VIO18_CON17		0x0322
+#define MT6397_VIO18_CON18		0x0324
+#define MT6397_VPCA7_CON0		0x0326
+#define MT6397_VPCA7_CON1		0x0328
+#define MT6397_VPCA7_CON2		0x032A
+#define MT6397_VPCA7_CON3		0x032C
+#define MT6397_VPCA7_CON4		0x032E
+#define MT6397_VPCA7_CON5		0x0330
+#define MT6397_VPCA7_CON6		0x0332
+#define MT6397_VPCA7_CON7		0x0334
+#define MT6397_VPCA7_CON8		0x0336
+#define MT6397_VPCA7_CON9		0x0338
+#define MT6397_VPCA7_CON10		0x033A
+#define MT6397_VPCA7_CON11		0x033C
+#define MT6397_VPCA7_CON12		0x033E
+#define MT6397_VPCA7_CON13		0x0340
+#define MT6397_VPCA7_CON14		0x0342
+#define MT6397_VPCA7_CON15		0x0344
+#define MT6397_VPCA7_CON16		0x0346
+#define MT6397_VPCA7_CON17		0x0348
+#define MT6397_VPCA7_CON18		0x034A
+#define MT6397_VSRMCA7_CON0		0x034C
+#define MT6397_VSRMCA7_CON1		0x034E
+#define MT6397_VSRMCA7_CON2		0x0350
+#define MT6397_VSRMCA7_CON3		0x0352
+#define MT6397_VSRMCA7_CON4		0x0354
+#define MT6397_VSRMCA7_CON5		0x0356
+#define MT6397_VSRMCA7_CON6		0x0358
+#define MT6397_VSRMCA7_CON7		0x035A
+#define MT6397_VSRMCA7_CON8		0x035C
+#define MT6397_VSRMCA7_CON9		0x035E
+#define MT6397_VSRMCA7_CON10		0x0360
+#define MT6397_VSRMCA7_CON11		0x0362
+#define MT6397_VSRMCA7_CON12		0x0364
+#define MT6397_VSRMCA7_CON13		0x0366
+#define MT6397_VSRMCA7_CON14		0x0368
+#define MT6397_VSRMCA7_CON15		0x036A
+#define MT6397_VSRMCA7_CON16		0x036C
+#define MT6397_VSRMCA7_CON17		0x036E
+#define MT6397_VSRMCA7_CON18		0x0370
+#define MT6397_VSRMCA7_CON19		0x0372
+#define MT6397_VSRMCA7_CON20		0x0374
+#define MT6397_VSRMCA7_CON21		0x0376
+#define MT6397_VDRM_CON0		0x0378
+#define MT6397_VDRM_CON1		0x037A
+#define MT6397_VDRM_CON2		0x037C
+#define MT6397_VDRM_CON3		0x037E
+#define MT6397_VDRM_CON4		0x0380
+#define MT6397_VDRM_CON5		0x0382
+#define MT6397_VDRM_CON6		0x0384
+#define MT6397_VDRM_CON7		0x0386
+#define MT6397_VDRM_CON8		0x0388
+#define MT6397_VDRM_CON9		0x038A
+#define MT6397_VDRM_CON10		0x038C
+#define MT6397_VDRM_CON11		0x038E
+#define MT6397_VDRM_CON12		0x0390
+#define MT6397_VDRM_CON13		0x0392
+#define MT6397_VDRM_CON14		0x0394
+#define MT6397_VDRM_CON15		0x0396
+#define MT6397_VDRM_CON16		0x0398
+#define MT6397_VDRM_CON17		0x039A
+#define MT6397_VDRM_CON18		0x039C
+#define MT6397_BUCK_K_CON0		0x039E
+#define MT6397_BUCK_K_CON1		0x03A0
+#define MT6397_ANALDO_CON0		0x0400
+#define MT6397_ANALDO_CON1		0x0402
+#define MT6397_ANALDO_CON2		0x0404
+#define MT6397_ANALDO_CON3		0x0406
+#define MT6397_ANALDO_CON4		0x0408
+#define MT6397_ANALDO_CON5		0x040A
+#define MT6397_ANALDO_CON6		0x040C
+#define MT6397_ANALDO_CON7		0x040E
+#define MT6397_DIGLDO_CON0		0x0410
+#define MT6397_DIGLDO_CON1		0x0412
+#define MT6397_DIGLDO_CON2		0x0414
+#define MT6397_DIGLDO_CON3		0x0416
+#define MT6397_DIGLDO_CON4		0x0418
+#define MT6397_DIGLDO_CON5		0x041A
+#define MT6397_DIGLDO_CON6		0x041C
+#define MT6397_DIGLDO_CON7		0x041E
+#define MT6397_DIGLDO_CON8		0x0420
+#define MT6397_DIGLDO_CON9		0x0422
+#define MT6397_DIGLDO_CON10		0x0424
+#define MT6397_DIGLDO_CON11		0x0426
+#define MT6397_DIGLDO_CON12		0x0428
+#define MT6397_DIGLDO_CON13		0x042A
+#define MT6397_DIGLDO_CON14		0x042C
+#define MT6397_DIGLDO_CON15		0x042E
+#define MT6397_DIGLDO_CON16		0x0430
+#define MT6397_DIGLDO_CON17		0x0432
+#define MT6397_DIGLDO_CON18		0x0434
+#define MT6397_DIGLDO_CON19		0x0436
+#define MT6397_DIGLDO_CON20		0x0438
+#define MT6397_DIGLDO_CON21		0x043A
+#define MT6397_DIGLDO_CON22		0x043C
+#define MT6397_DIGLDO_CON23		0x043E
+#define MT6397_DIGLDO_CON24		0x0440
+#define MT6397_DIGLDO_CON25		0x0442
+#define MT6397_DIGLDO_CON26		0x0444
+#define MT6397_DIGLDO_CON27		0x0446
+#define MT6397_DIGLDO_CON28		0x0448
+#define MT6397_DIGLDO_CON29		0x044A
+#define MT6397_DIGLDO_CON30		0x044C
+#define MT6397_DIGLDO_CON31		0x044E
+#define MT6397_DIGLDO_CON32		0x0450
+#define MT6397_DIGLDO_CON33		0x045A
+#define MT6397_SPK_CON0			0x0600
+#define MT6397_SPK_CON1			0x0602
+#define MT6397_SPK_CON2			0x0604
+#define MT6397_SPK_CON3			0x0606
+#define MT6397_SPK_CON4			0x0608
+#define MT6397_SPK_CON5			0x060A
+#define MT6397_SPK_CON6			0x060C
+#define MT6397_SPK_CON7			0x060E
+#define MT6397_SPK_CON8			0x0610
+#define MT6397_SPK_CON9			0x0612
+#define MT6397_SPK_CON10		0x0614
+#define MT6397_SPK_CON11		0x0616
+#define MT6397_AUDDAC_CON0		0x0700
+#define MT6397_AUDBUF_CFG0		0x0702
+#define MT6397_AUDBUF_CFG1		0x0704
+#define MT6397_AUDBUF_CFG2		0x0706
+#define MT6397_AUDBUF_CFG3		0x0708
+#define MT6397_AUDBUF_CFG4		0x070A
+#define MT6397_IBIASDIST_CFG0		0x070C
+#define MT6397_AUDACCDEPOP_CFG0		0x070E
+#define MT6397_AUD_IV_CFG0		0x0710
+#define MT6397_AUDCLKGEN_CFG0		0x0712
+#define MT6397_AUDLDO_CFG0		0x0714
+#define MT6397_AUDLDO_CFG1		0x0716
+#define MT6397_AUDNVREGGLB_CFG0		0x0718
+#define MT6397_AUD_NCP0			0x071A
+#define MT6397_AUDPREAMP_CON0		0x071C
+#define MT6397_AUDADC_CON0		0x071E
+#define MT6397_AUDADC_CON1		0x0720
+#define MT6397_AUDADC_CON2		0x0722
+#define MT6397_AUDADC_CON3		0x0724
+#define MT6397_AUDADC_CON4		0x0726
+#define MT6397_AUDADC_CON5		0x0728
+#define MT6397_AUDADC_CON6		0x072A
+#define MT6397_AUDDIGMI_CON0		0x072C
+#define MT6397_AUDLSBUF_CON0		0x072E
+#define MT6397_AUDLSBUF_CON1		0x0730
+#define MT6397_AUDENCSPARE_CON0		0x0732
+#define MT6397_AUDENCCLKSQ_CON0		0x0734
+#define MT6397_AUDPREAMPGAIN_CON0	0x0736
+#define MT6397_ZCD_CON0			0x0738
+#define MT6397_ZCD_CON1			0x073A
+#define MT6397_ZCD_CON2			0x073C
+#define MT6397_ZCD_CON3			0x073E
+#define MT6397_ZCD_CON4			0x0740
+#define MT6397_ZCD_CON5			0x0742
+#define MT6397_NCP_CLKDIV_CON0		0x0744
+#define MT6397_NCP_CLKDIV_CON1		0x0746
+
+#endif /* __MFD_MT6397_REGISTERS_H__ */
-- 
2.1.4


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 09/13] ARM: dts: mediatek: Enable clock support for Mediatek MT8135.
  2015-02-09 10:47 ` [PATCH 09/13] ARM: dts: mediatek: Enable clock support for Mediatek MT8135 Sascha Hauer
@ 2015-02-09 10:51   ` Russell King - ARM Linux
  2015-02-09 11:25     ` Sascha Hauer
  0 siblings, 1 reply; 27+ messages in thread
From: Russell King - ARM Linux @ 2015-02-09 10:51 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: Matthias Brugger, James Liao, Mike Turquette,
	YH Chen (陳昱豪),
	linux-kernel, Henry Chen, Rob Herring, kernel,
	Yingjoe Chen (陳英洲),
	Eddie Huang, Lee Jones, linux-arm-kernel

On Mon, Feb 09, 2015 at 11:47:21AM +0100, Sascha Hauer wrote:
> From: James Liao <jamesjj.liao@mediatek.com>
> 
> This patch adds MT8135 clock controllers into device tree.
> @@ -86,6 +87,18 @@
>  			clock-frequency = <32000>;
>  			#clock-cells = <0>;
>  		};
> +
> +		clk_null: clk_null {
> +			compatible = "fixed-clock";
> +			#clock-cells = <0>;
> +			clock-frequency = <0>;
> +		};
> +
> +		clk26m: clk26m {
> +			compatible = "fixed-clock";
> +			#clock-cells = <0>;
> +			clock-frequency = <26000000>;
> +		};

Is this supposed to be here?

-- 
FTTC broadband for 0.8mile line: currently at 10.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 09/13] ARM: dts: mediatek: Enable clock support for Mediatek MT8135.
  2015-02-09 10:51   ` Russell King - ARM Linux
@ 2015-02-09 11:25     ` Sascha Hauer
  2015-02-09 11:27       ` Russell King - ARM Linux
  0 siblings, 1 reply; 27+ messages in thread
From: Sascha Hauer @ 2015-02-09 11:25 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: Matthias Brugger, James Liao, Mike Turquette,
	YH Chen (陳昱豪),
	linux-kernel, Henry Chen, Rob Herring, kernel,
	Yingjoe Chen (陳英洲),
	Eddie Huang, Lee Jones, linux-arm-kernel

On Mon, Feb 09, 2015 at 10:51:34AM +0000, Russell King - ARM Linux wrote:
> On Mon, Feb 09, 2015 at 11:47:21AM +0100, Sascha Hauer wrote:
> > From: James Liao <jamesjj.liao@mediatek.com>
> > 
> > This patch adds MT8135 clock controllers into device tree.
> > @@ -86,6 +87,18 @@
> >  			clock-frequency = <32000>;
> >  			#clock-cells = <0>;
> >  		};
> > +
> > +		clk_null: clk_null {
> > +			compatible = "fixed-clock";
> > +			#clock-cells = <0>;
> > +			clock-frequency = <0>;
> > +		};
> > +
> > +		clk26m: clk26m {
> > +			compatible = "fixed-clock";
> > +			#clock-cells = <0>;
> > +			clock-frequency = <26000000>;
> > +		};
> 
> Is this supposed to be here?

The clock support needs at least the clk26m clk. Do you think it should
be in another patch or not present at all?

Sascha


-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 09/13] ARM: dts: mediatek: Enable clock support for Mediatek MT8135.
  2015-02-09 11:25     ` Sascha Hauer
@ 2015-02-09 11:27       ` Russell King - ARM Linux
  2015-02-09 11:44         ` Sascha Hauer
  0 siblings, 1 reply; 27+ messages in thread
From: Russell King - ARM Linux @ 2015-02-09 11:27 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: Matthias Brugger, James Liao, Mike Turquette,
	YH Chen (陳昱豪),
	linux-kernel, Henry Chen, Rob Herring, kernel,
	Yingjoe Chen (陳英洲),
	Eddie Huang, Lee Jones, linux-arm-kernel

On Mon, Feb 09, 2015 at 12:25:00PM +0100, Sascha Hauer wrote:
> On Mon, Feb 09, 2015 at 10:51:34AM +0000, Russell King - ARM Linux wrote:
> > On Mon, Feb 09, 2015 at 11:47:21AM +0100, Sascha Hauer wrote:
> > > From: James Liao <jamesjj.liao@mediatek.com>
> > > 
> > > This patch adds MT8135 clock controllers into device tree.
> > > @@ -86,6 +87,18 @@
> > >  			clock-frequency = <32000>;
> > >  			#clock-cells = <0>;
> > >  		};
> > > +
> > > +		clk_null: clk_null {
> > > +			compatible = "fixed-clock";
> > > +			#clock-cells = <0>;
> > > +			clock-frequency = <0>;
> > > +		};
> > > +
> > > +		clk26m: clk26m {
> > > +			compatible = "fixed-clock";
> > > +			#clock-cells = <0>;
> > > +			clock-frequency = <26000000>;
> > > +		};
> > 
> > Is this supposed to be here?
> 
> The clock support needs at least the clk26m clk. Do you think it should
> be in another patch or not present at all?

I didn't see anything which referenced either clk_null or clk26m in this
patch.  My main concern was that clk_null, but my concern grew when I
found that clk26m wasn't referenced either.

If the MT8135 needs it, shouldn't something in its description reference
this clock?

-- 
FTTC broadband for 0.8mile line: currently at 10.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 09/13] ARM: dts: mediatek: Enable clock support for Mediatek MT8135.
  2015-02-09 11:27       ` Russell King - ARM Linux
@ 2015-02-09 11:44         ` Sascha Hauer
  0 siblings, 0 replies; 27+ messages in thread
From: Sascha Hauer @ 2015-02-09 11:44 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: James Liao, Mike Turquette, YH Chen (陳昱豪),
	linux-kernel, Henry Chen, Rob Herring, kernel, Matthias Brugger,
	Yingjoe Chen (陳英洲),
	Eddie Huang, Lee Jones, linux-arm-kernel

On Mon, Feb 09, 2015 at 11:27:21AM +0000, Russell King - ARM Linux wrote:
> On Mon, Feb 09, 2015 at 12:25:00PM +0100, Sascha Hauer wrote:
> > On Mon, Feb 09, 2015 at 10:51:34AM +0000, Russell King - ARM Linux wrote:
> > > On Mon, Feb 09, 2015 at 11:47:21AM +0100, Sascha Hauer wrote:
> > > > From: James Liao <jamesjj.liao@mediatek.com>
> > > > 
> > > > This patch adds MT8135 clock controllers into device tree.
> > > > @@ -86,6 +87,18 @@
> > > >  			clock-frequency = <32000>;
> > > >  			#clock-cells = <0>;
> > > >  		};
> > > > +
> > > > +		clk_null: clk_null {
> > > > +			compatible = "fixed-clock";
> > > > +			#clock-cells = <0>;
> > > > +			clock-frequency = <0>;
> > > > +		};
> > > > +
> > > > +		clk26m: clk26m {
> > > > +			compatible = "fixed-clock";
> > > > +			#clock-cells = <0>;
> > > > +			clock-frequency = <26000000>;
> > > > +		};
> > > 
> > > Is this supposed to be here?
> > 
> > The clock support needs at least the clk26m clk. Do you think it should
> > be in another patch or not present at all?
> 
> I didn't see anything which referenced either clk_null or clk26m in this
> patch.  My main concern was that clk_null, but my concern grew when I
> found that clk26m wasn't referenced either.
> 
> If the MT8135 needs it, shouldn't something in its description reference
> this clock?

It's used in the code. The mt8135 clk code directly uses the names of
these three clocks as parent_names.

Sascha


-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 01/13] clk: dts: mediatek: add Mediatek MT8135 clock bindings
  2015-02-09 10:47 ` [PATCH 01/13] clk: dts: mediatek: add Mediatek MT8135 clock bindings Sascha Hauer
@ 2015-02-09 13:35   ` Philipp Zabel
  0 siblings, 0 replies; 27+ messages in thread
From: Philipp Zabel @ 2015-02-09 13:35 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: Matthias Brugger, James Liao, Mike Turquette,
	YH Chen (陳昱豪),
	linux-kernel, Henry Chen, Rob Herring, kernel,
	Yingjoe Chen (陳英洲),
	Eddie Huang, Lee Jones, linux-arm-kernel

Am Montag, den 09.02.2015, 11:47 +0100 schrieb Sascha Hauer:
> From: James Liao <jamesjj.liao@mediatek.com>
> 
> Document the device-tree binding of Mediatek MT8135 SoC, including
> TOPCKGEN, PLLs, INFRA and PERI clock controller.
> 
> 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>
> ---
>  .../bindings/clock/mediatek,mt8135-clock.txt       |  44 +++++
>  include/dt-bindings/clock/mt8135-clk.h             | 190 +++++++++++++++++++++
>  2 files changed, 234 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/clock/mediatek,mt8135-clock.txt
>  create mode 100644 include/dt-bindings/clock/mt8135-clk.h
> 
> diff --git a/Documentation/devicetree/bindings/clock/mediatek,mt8135-clock.txt b/Documentation/devicetree/bindings/clock/mediatek,mt8135-clock.txt
> new file mode 100644
> index 0000000..1e3566f
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/clock/mediatek,mt8135-clock.txt
> @@ -0,0 +1,44 @@
> +Mediatek MT8135 Clock Controller
> +
> +This binding uses the common clock binding:
> +Documentation/devicetree/bindings/clock/clock-bindings.txt
> +
> +The Mediatek MT8135 clock controller generates and supplies clock to various
> +controllers within Mediatek MT8135 SoC.
> +
> +Required Properties:
> +
> +- compatible: should be one of following:
> +	- "mediatek,mt8135-topckgen" : for topckgen clock controller of MT8135.
> +	- "mediatek,mt8135-apmixedsys" : for apmixed_sys (PLLs) of MT8135.
> +	- "mediatek,mt8135-infracfg" : for infra_sys clock controller of MT8135.
> +	- "mediatek,mt8135-pericfg" : for peri_sys clock controller of MT8135.
> +
> +- reg: physical base address of the controller and length of memory mapped
> +  region.
> +
> +- #clock-cells: should be 1.

After patch 3 ("clk: mediatek: Add reset controller support"), there's
another required property:

- #reset-cells: should be 1.

Patch 9 ("ARM: dts: mediatek: Enable clock support for Mediatek
MT8135.") already correctly includes these in the dtsi.

regards
Philipp


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 03/13] clk: mediatek: Add reset controller support
  2015-02-09 10:47 ` [PATCH 03/13] clk: mediatek: Add reset controller support Sascha Hauer
@ 2015-02-09 13:35   ` Philipp Zabel
  0 siblings, 0 replies; 27+ messages in thread
From: Philipp Zabel @ 2015-02-09 13:35 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: Matthias Brugger, Mike Turquette,
	YH Chen (陳昱豪),
	linux-kernel, Henry Chen, Rob Herring, kernel,
	Yingjoe Chen (陳英洲),
	Eddie Huang, Lee Jones, linux-arm-kernel

Am Montag, den 09.02.2015, 11:47 +0100 schrieb Sascha Hauer:
> The pericfg and infracfg units also provide reset lines to several
> other SoC internal units. Add support for the reset controller.
> 
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>

Acked-by: Philipp Zabel <p.zabel@pengutronix.de>

regards
Philipp


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 02/13] clk: mediatek: Add initial common clock support for Mediatek SoCs.
  2015-02-09 10:47 ` [PATCH 02/13] clk: mediatek: Add initial common clock support for Mediatek SoCs Sascha Hauer
@ 2015-02-13  7:41   ` Tomasz Figa
  2015-02-13 12:06     ` Sascha Hauer
  0 siblings, 1 reply; 27+ messages in thread
From: Tomasz Figa @ 2015-02-13  7:41 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: Matthias Brugger, James Liao, Mike Turquette,
	YH Chen (陳昱豪),
	linux-kernel, Henry Chen, Rob Herring, kernel,
	Yingjoe Chen (陳英洲),
	Eddie Huang, Lee Jones, linux-arm-kernel

Hi,

Let me add some suggestions inline.

On Mon, Feb 9, 2015 at 7:47 PM, Sascha Hauer <s.hauer@pengutronix.de> wrote:
> From: James Liao <jamesjj.liao@mediatek.com>
>
> This patch adds common clock support for Mediatek SoCs, including plls,
> muxes and clock gates.

[snip]

> +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);
> +}

Instead of duplicating the ops, couldn't you add a flag or something
to mtk_clk_gate struct and then act appropriately in the ops? Also,
see below.

> +
> +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)

Instead of passing the ops here you would have some flags or even just
a single bool inverted. Then the ops struct could be made static.

Also it would be nice to have a kerneldoc-style comment documenting
arguments of this function. Same thing applies to other structs added
by this and related patches and non-static functions.

also CodingStyle: I believe it is not kernel coding style to push
every argument to new line, even if few of them can fit one line.
Similar thing applies to other functions added by this and related
patches using this convention.

> +{
> +       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..a44dcbf
> --- /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>

Might not be necessary, but maybe the other people (all or some of
them) from signed-off-by should be added to this and other copyright
statements?

> + *
> + * 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
> +
> +/*
> + * This is a private header file. DO NOT include it except clk-*.c.
> + */

I believe the above comment is unnecessary, because the file is
already located in drivers/clk/mediatek.

> +#include <linux/regmap.h>
> +#include <linux/clk.h>
> +#include <linux/clk-provider.h>
> +
> +struct mtk_clk_gate {

It would be nice to have a kerneldoc-style comment describing fields
of this struct.

> +       struct clk_hw   hw;
> +       struct regmap   *regmap;
> +       int             set_ofs;
> +       int             clr_ofs;
> +       int             sta_ofs;
> +       u8              bit;
> +};
> +
> +#define to_clk_gate(_hw) container_of(_hw, struct mtk_clk_gate, hw)

I believe static inline is preferred to macros for such helpers, due
to increased type safety.

> +
> +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..479857c
> --- /dev/null
> +++ b/drivers/clk/mediatek/clk-mtk.c
> @@ -0,0 +1,155 @@
> +/*
> + * 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"
> +
> +void mtk_init_factors(struct mtk_fixed_factor *clks, int num,
> +               struct clk_onecell_data *clk_data)
> +{
> +       int i;
> +       struct clk *clk;
> +
> +       for (i = 0; i < num; i++) {
> +               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;
> +       }
> +}
> +
> +void mtk_init_clk_gates(struct regmap *regmap,
> +               struct mtk_gate *clks, int num,
> +               struct clk_onecell_data *clk_data)
> +{
> +       int i;
> +       struct clk *clk;
> +
> +       for (i = 0; i < num; i++) {
> +               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;
> +               }
> +
> +               if (clk_data)
> +                       clk_data->clks[gate->id] = clk;
> +       }
> +}
> +
> +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);

Shouldn't it be sizeof(*clk_data)?

> +       if (!clk_data)
> +               return NULL;
> +
> +       clk_data->clks = kcalloc(clk_num, sizeof(struct clk *), GFP_KERNEL);

sizeof(*clk_data->clks)

> +       if (!clk_data->clks) {
> +               kfree(clk_data);
> +               return NULL;
> +       }
> +
> +       clk_data->clk_num = clk_num;
> +
> +       for (i = 0; i < clk_num; ++i)
> +               clk_data->clks[i] = ERR_PTR(-ENOENT);
> +
> +       return clk_data;
> +}
> +
> +struct clk *mtk_clk_register_mux(
> +               const char *name,
> +               const char **parent_names,
> +               u8 num_parents,
> +               void __iomem *base_addr,
> +               u8 shift,
> +               u8 width,
> +               u8 gate_bit,
> +               spinlock_t *lock)
> +{
> +       struct clk *clk;
> +       struct clk_mux *mux;
> +       struct clk_gate *gate = NULL;
> +       struct clk_hw *gate_hw = NULL;
> +       const struct clk_ops *gate_ops = NULL;
> +       u32 mask = BIT(width) - 1;
> +
> +       mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL);

sizeof(*mux)

> +       if (!mux)
> +               return ERR_PTR(-ENOMEM);
> +
> +       mux->reg = base_addr;
> +       mux->mask = mask;
> +       mux->shift = shift;
> +       mux->flags = 0;

Flags field was already zeroed by kzalloc().

> +       mux->lock = lock;
> +
> +       if (gate_bit <= MAX_MUX_GATE_BIT) {
> +               gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL);

sizeof(*gate)

> +               if (!gate) {
> +                       kfree(mux);

Please use goto style error path below the main code instead of
duplicating roll-back actions in every error check.

> +                       return ERR_PTR(-ENOMEM);
> +               }
> +
> +               gate->reg = base_addr;
> +               gate->bit_idx = gate_bit;
> +               gate->flags = CLK_GATE_SET_TO_DISABLE;
> +               gate->lock = lock;
> +
> +               gate_hw = &gate->hw;
> +               gate_ops = &clk_gate_ops;
> +       }
> +
> +       clk = clk_register_composite(NULL, name, parent_names, num_parents,
> +               &mux->hw, &clk_mux_ops,
> +               NULL, NULL,
> +               gate_hw, gate_ops,
> +               CLK_SET_RATE_PARENT);
> +
> +       if (IS_ERR(clk)) {
> +               kfree(gate);
> +               kfree(mux);
> +       }
> +
> +       return clk;
> +}
> diff --git a/drivers/clk/mediatek/clk-mtk.h b/drivers/clk/mediatek/clk-mtk.h
> new file mode 100644
> index 0000000..35cf9a3
> --- /dev/null
> +++ b/drivers/clk/mediatek/clk-mtk.h
> @@ -0,0 +1,133 @@
> +/*
> + * 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
> +
> +/*
> + * This is a private header file. DO NOT include it except clk-*.c.
> + */
> +
> +#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)

It might be a good idea to describe what this value is used for.

> +
> +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_init_factors(struct mtk_fixed_factor *clks, int num,
> +               struct clk_onecell_data *clk_data);
> +
> +struct mtk_mux {
> +       int id;
> +       const char *name;
> +       uint32_t reg;
> +       int shift;
> +       int width;
> +       int gate;
> +       const char **parent_names;
> +       int num_parents;
> +};
> +
> +#define MUX(_id, _name, _parents, _reg, _shift, _width, _gate) {       \
> +               .id = _id,                                              \
> +               .name = _name,                                          \
> +               .reg = _reg,                                            \
> +               .shift = _shift,                                        \
> +               .width = _width,                                        \
> +               .gate = _gate,                                          \
> +               .parent_names = (const char **)_parents,                \

Hmm, it doesn't sound like a good idea to hide casts like this inside
a macro. Anyway, is this cast even necessary? Your _parents argument
to this macro should be always of correct type.

> +               .num_parents = ARRAY_SIZE(_parents),                    \
> +       }
> +
> +struct mtk_pll {
> +       int id;
> +       const char *name;
> +       const char *parent_name;
> +       uint32_t reg;
> +       uint32_t pwr_reg;
> +       uint32_t en_mask;
> +       unsigned int flags;
> +       const struct clk_ops *ops;
> +};
> +
> +#define PLL(_id, _name, _parent, _reg, _pwr_reg, _en_mask, _flags, _ops) { \
> +               .id = _id,                                              \
> +               .name = _name,                                          \
> +               .parent_name = _parent,                                 \
> +               .reg = _reg,                                            \
> +               .pwr_reg = _pwr_reg,                                    \
> +               .en_mask = _en_mask,                                    \
> +               .flags = _flags,                                        \
> +               .ops = _ops,                                            \
> +       }
> +
> +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;
> +       struct mtk_gate_regs *regs;
> +       int shift;
> +       const struct clk_ops *ops;
> +};
> +
> +#define GATE(_id, _name, _parent, _regs, _shift, _ops) {       \
> +               .id = _id,                                      \
> +               .name = _name,                                  \
> +               .parent_name = _parent,                         \
> +               .regs = &_regs,                                 \

Also hiding operators like & inside macros like this doesn't help with
code readability and it doesn't cost that much to just add & when
calling this macro.

> +               .shift = _shift,                                \
> +               .ops = _ops,                                    \
> +       }
> +
> +void mtk_init_clk_gates(struct regmap *regmap,
> +               struct mtk_gate *clks, int num,
> +               struct clk_onecell_data *clk_data);
> +
> +struct clk_onecell_data *mtk_alloc_clk_data(unsigned int clk_num);
> +
> +struct clk *mtk_clk_register_mux(
> +               const char *name,
> +               const char **parent_names,
> +               u8 num_parents,
> +               void __iomem *base_addr,
> +               u8 shift,
> +               u8 width,
> +               u8 gate_bit,
> +               spinlock_t *lock);
> +
> +#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..59dee83
> --- /dev/null
> +++ b/drivers/clk/mediatek/clk-pll.c
> @@ -0,0 +1,63 @@
> +/*
> + * 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/io.h>
> +#include <linux/slab.h>
> +#include <linux/clkdev.h>
> +
> +#include "clk-mtk.h"
> +#include "clk-pll.h"
> +
> +struct clk *mtk_clk_register_pll(
> +               const char *name,
> +               const char *parent_name,
> +               u32 *base_addr,
> +               u32 *pwr_addr,
> +               u32 en_mask,
> +               u32 flags,
> +               const struct clk_ops *ops,
> +               spinlock_t *lock)
> +{
> +       struct mtk_clk_pll *pll;
> +       struct clk_init_data init;
> +       struct clk *clk;
> +
> +       pr_debug("%s(): name: %s\n", __func__, name);
> +
> +       if (!lock)
> +               return ERR_PTR(-EINVAL);

Hmm, this check seems to be slightly inconsistent. Why you need to
check lock, but not name, parent_name and other arguments of this
function? Also bailing out without any error message isn't really the
best practice.

Anyway, if this function is defined to require the lock argument to be
non-NULL then this is not a natural error condition but rather a
mistake of the author of code calling this function with lock == NULL.
IMHO either BUG_ON(!lock) or just remove this check, but I'd like to
know Mike's thoughts on this before you make this change.

> +
> +       pll = kzalloc(sizeof(*pll), GFP_KERNEL);
> +       if (!pll)
> +               return ERR_PTR(-ENOMEM);
> +
> +       pll->base_addr = base_addr;
> +       pll->pwr_addr = pwr_addr;
> +       pll->en_mask = en_mask;
> +       pll->flags = flags;
> +       pll->lock = lock;
> +       pll->hw.init = &init;
> +
> +       init.name = name;
> +       init.ops = ops;
> +       init.parent_names = &parent_name;
> +       init.num_parents = 1;
> +
> +       clk = clk_register(NULL, &pll->hw);
> +
> +       if (IS_ERR(clk))
> +               kfree(pll);
> +
> +       return clk;
> +}
> diff --git a/drivers/clk/mediatek/clk-pll.h b/drivers/clk/mediatek/clk-pll.h
> new file mode 100644
> index 0000000..341d2fe
> --- /dev/null
> +++ b/drivers/clk/mediatek/clk-pll.h
> @@ -0,0 +1,52 @@
> +/*
> + * 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_PLL_H
> +#define __DRV_CLK_PLL_H
> +
> +/*
> + * This is a private header file. DO NOT include it except clk-*.c.
> + */
> +
> +#include <linux/bitops.h>
> +#include <linux/clk.h>
> +#include <linux/clk-provider.h>
> +
> +struct mtk_clk_pll {
> +       struct clk_hw   hw;
> +       void __iomem    *base_addr;
> +       void __iomem    *pwr_addr;
> +       u32             en_mask;
> +       u32             flags;
> +       spinlock_t      *lock;
> +};
> +
> +#define to_mtk_clk_pll(_hw) container_of(_hw, struct mtk_clk_pll, hw)

Static inline please.

Best regards,
Tomasz

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 06/13] clk: mediatek: Add basic clocks for Mediatek MT8173.
  2015-02-09 10:47 ` [PATCH 06/13] clk: mediatek: Add basic clocks for Mediatek MT8173 Sascha Hauer
@ 2015-02-13  9:56   ` Tomasz Figa
  2015-02-19  8:24     ` Sascha Hauer
  0 siblings, 1 reply; 27+ messages in thread
From: Tomasz Figa @ 2015-02-13  9:56 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: Matthias Brugger, James Liao, Mike Turquette,
	YH Chen (陳昱豪),
	linux-kernel, Henry Chen, Rob Herring, kernel,
	Yingjoe Chen (陳英洲),
	Eddie Huang, Lee Jones, linux-arm-kernel

Please find my comments inline.

On Mon, Feb 9, 2015 at 7:47 PM, Sascha Hauer <s.hauer@pengutronix.de> wrote:
> From: James Liao <jamesjj.liao@mediatek.com>
>
> 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-pll.c |  807 +++++++++++++++++++++++++
>  drivers/clk/mediatek/clk-mt8173-pll.h |   14 +
>  drivers/clk/mediatek/clk-mt8173.c     | 1035 +++++++++++++++++++++++++++++++++
>  4 files changed, 1857 insertions(+)
>  create mode 100644 drivers/clk/mediatek/clk-mt8173-pll.c
>  create mode 100644 drivers/clk/mediatek/clk-mt8173-pll.h
>  create mode 100644 drivers/clk/mediatek/clk-mt8173.c
>
> diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile
> index afb52e5..e030416 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 clk-mt8135-pll.o
> +obj-y += clk-mt8173.o clk-mt8173-pll.o
> diff --git a/drivers/clk/mediatek/clk-mt8173-pll.c b/drivers/clk/mediatek/clk-mt8173-pll.c
> new file mode 100644
> index 0000000..9f6f821
> --- /dev/null
> +++ b/drivers/clk/mediatek/clk-mt8173-pll.c
> @@ -0,0 +1,807 @@
> +/*
> + * 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/io.h>
> +#include <linux/slab.h>
> +#include <linux/delay.h>
> +#include <linux/clkdev.h>
> +
> +#include "clk-mtk.h"
> +#include "clk-pll.h"
> +#include "clk-mt8173-pll.h"
> +
> +#define PLL_BASE_EN    BIT(0)
> +#define PLL_PWR_ON     BIT(0)
> +#define PLL_ISO_EN     BIT(1)
> +#define PLL_PCW_CHG    BIT(31)
> +#define RST_BAR_MASK   BIT(24)
> +#define AUDPLL_TUNER_EN        BIT(31)
> +
> +static const u32 pll_posdiv_map[8] = { 1, 2, 4, 8, 16, 16, 16, 16 };

It might be nice to have a comment what this array is for and how the
values were calculated.

> +
> +static u32 mtk_calc_pll_vco_freq(
> +               u32 fin,
> +               u32 pcw,
> +               u32 vcodivsel,
> +               u32 prediv,
> +               u32 pcwfbits)
> +{
> +       /* vco = (fin * pcw * vcodivsel / prediv) >> pcwfbits; */
> +       u64 vco = fin;
> +       u8 c = 0;
> +
> +       vco = vco * pcw * vcodivsel;

Could you use here (u64)fin directly for increased readability and
drop the initialization of vco?

> +       do_div(vco, prediv);
> +
> +       if (vco & GENMASK(pcwfbits - 1, 0))
> +               c = 1;

What is c? Could the variable has a more meaningful name?

> +
> +       vco >>= pcwfbits;
> +
> +       if (c)
> +               ++vco;
> +
> +       return (u32)vco;
> +}
> +
> +static u32 mtk_freq_limit(u32 freq)
> +{
> +       static const u64 freq_max = 3000UL * 1000 * 1000;       /* 3000 MHz */

3 GHz probably? Could you define (if not defined somewhere already) a
macro for GHZ and write this as 3 * GHZ?

> +       static const u32 freq_min = 1000 * 1000 * 1000 / 16;    /* 62.5 MHz */

Why don't you write it as 62500 * KHZ or 62 * MHZ + 500 * KHZ?

> +
> +       if (freq <= freq_min)
> +               freq = freq_min + 16;

Could you explain what's happening here? Where does the 16 come from
and why it is not defined as a macro?

> +       else if (freq > freq_max)
> +               freq = freq_max;
> +
> +       return freq;
> +}
> +
> +static int mtk_calc_pll_freq_cfg(
> +               u32 *pcw,
> +               u32 *postdiv_idx,
> +               u32 freq,
> +               u32 fin,
> +               int pcwfbits)
> +{
> +       static const u64 freq_max = 3000UL * 1000 * 1000;       /* 3000 MHz */
> +       static const u64 freq_min = 1000 * 1000 * 1000;         /* 1000 MHz */
> +       static const u64 postdiv[] = { 1, 2, 4, 8, 16 };
> +       u64 n_info;
> +       u32 idx;
> +
> +       /* search suitable postdiv */
> +       for (idx = *postdiv_idx;
> +               idx < ARRAY_SIZE(postdiv) && postdiv[idx] * freq <= freq_min;
> +               idx++)
> +               ;

Please document the arguments of this function. It is not obvious why
the value at postdiv_idx is used as starting point, even though this
pointer is also used to store the output value...

> +
> +       if (idx >= ARRAY_SIZE(postdiv))
> +               return -EINVAL; /* freq is out of range (too low) */
> +       else if (postdiv[idx] * freq > freq_max)
> +               return -EINVAL; /* freq is out of range (too high) */
> +
> +       /* n_info = freq * postdiv / 26MHz * 2^pcwfbits */
> +       n_info = (postdiv[idx] * freq) << pcwfbits;
> +       do_div(n_info, fin);
> +
> +       *postdiv_idx = idx;
> +       *pcw = (u32)n_info;
> +
> +       return 0;
> +}
> +
> +static int mtk_clk_pll_is_enabled(struct clk_hw *hw)
> +{
> +       struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
> +
> +       return (readl_relaxed(pll->base_addr) & PLL_BASE_EN) != 0;
> +}
> +
> +static int mtk_clk_pll_prepare(struct clk_hw *hw)

Hmm, contents of this function don't seem to sleep. Maybe this should
be enable instead of prepare?

> +{
> +       unsigned long flags = 0;

No need to initialize.

> +       struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
> +       u32 r;
> +
> +       spin_lock_irqsave(pll->lock, flags);
> +
> +       r = readl_relaxed(pll->pwr_addr) | PLL_PWR_ON;
> +       writel_relaxed(r, pll->pwr_addr);
> +       wmb();  /* sync write before delay */
> +       udelay(1);
> +
> +       r = readl_relaxed(pll->pwr_addr) & ~PLL_ISO_EN;
> +       writel_relaxed(r, pll->pwr_addr);
> +       wmb();  /* sync write before delay */
> +       udelay(1);
> +
> +       r = readl_relaxed(pll->base_addr) | pll->en_mask;
> +       writel_relaxed(r, pll->base_addr);
> +       wmb();  /* sync write before delay */
> +       udelay(20);
> +
> +       if (pll->flags & HAVE_RST_BAR) {
> +               r = readl_relaxed(pll->base_addr) | RST_BAR_MASK;
> +               writel_relaxed(r, pll->base_addr);
> +       }
> +
> +       spin_unlock_irqrestore(pll->lock, flags);
> +
> +       return 0;
> +}
> +
> +static void mtk_clk_pll_unprepare(struct clk_hw *hw)

Similarly to prepare, maybe you should consider to implement disable
instead of unprepare.

> +{
> +       unsigned long flags = 0;

No need to initialize.

> +       struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
> +       u32 r;
> +
> +       if (pll->flags & PLL_AO)
> +               return;
> +
> +       spin_lock_irqsave(pll->lock, flags);
> +
> +       if (pll->flags & HAVE_RST_BAR) {
> +               r = readl_relaxed(pll->base_addr) & ~RST_BAR_MASK;
> +               writel_relaxed(r, pll->base_addr);
> +       }
> +
> +       r = readl_relaxed(pll->base_addr) & ~PLL_BASE_EN;
> +       writel_relaxed(r, pll->base_addr);
> +
> +       r = readl_relaxed(pll->pwr_addr) | PLL_ISO_EN;
> +       writel_relaxed(r, pll->pwr_addr);
> +
> +       r = readl_relaxed(pll->pwr_addr) & ~PLL_PWR_ON;
> +       writel_relaxed(r, pll->pwr_addr);
> +
> +       spin_unlock_irqrestore(pll->lock, flags);
> +}
> +
> +static long mtk_clk_pll_round_rate(
> +               struct clk_hw *hw,
> +               unsigned long rate,
> +               unsigned long *prate)
> +{
> +       u32 pcwfbits = 14;
> +       u32 pcw = 0;
> +       u32 postdiv = 0;
> +       u32 r;
> +
> +       *prate = *prate ? *prate : 26000000;
> +       rate = mtk_freq_limit(rate);
> +       mtk_calc_pll_freq_cfg(&pcw, &postdiv, rate, *prate, pcwfbits);
> +
> +       r = mtk_calc_pll_vco_freq(*prate, pcw, 1, 1, pcwfbits);
> +       r = (r + pll_posdiv_map[postdiv] - 1) / pll_posdiv_map[postdiv];
> +
> +       return r;
> +}
> +
> +#define SDM_PLL_POSTDIV_H      6
> +#define SDM_PLL_POSTDIV_L      4
> +#define SDM_PLL_POSTDIV_MASK   GENMASK(SDM_PLL_POSTDIV_H, SDM_PLL_POSTDIV_L)
> +#define SDM_PLL_PCW_H          20
> +#define SDM_PLL_PCW_L          0
> +#define SDM_PLL_PCW_MASK       GENMASK(SDM_PLL_PCW_H, SDM_PLL_PCW_L)
> +
> +static unsigned long mtk_clk_sdm_pll_recalc_rate(
> +               struct clk_hw *hw,
> +               unsigned long parent_rate)
> +{
> +       struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
> +
> +       u32 con0 = readl_relaxed(pll->base_addr);
> +       u32 con1 = readl_relaxed(pll->base_addr + 4);
> +
> +       u32 posdiv = (con0 & SDM_PLL_POSTDIV_MASK) >> SDM_PLL_POSTDIV_L;
> +       u32 pcw = (con1 & SDM_PLL_PCW_MASK) >> SDM_PLL_PCW_L;
> +       u32 pcwfbits = 14;
> +
> +       u32 vco_freq;
> +       unsigned long r;
> +
> +       parent_rate = parent_rate ? parent_rate : 26000000;
> +
> +       vco_freq = mtk_calc_pll_vco_freq(parent_rate, pcw, 1, 1, pcwfbits);
> +       r = (vco_freq + pll_posdiv_map[posdiv] - 1) / pll_posdiv_map[posdiv];
> +
> +       return r;
> +}
> +
> +static void mtk_clk_sdm_pll_set_rate_regs(
> +               struct clk_hw *hw,
> +               u32 pcw,
> +               u32 postdiv_idx)
> +{
> +       unsigned long flags = 0;

No need to initialize.

> +       struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
> +       void __iomem *con0_addr = pll->base_addr;
> +       void __iomem *con1_addr = pll->base_addr + 4;
> +       u32 con0;
> +       u32 con1;
> +       u32 pll_en;
> +
> +       spin_lock_irqsave(pll->lock, flags);
> +
> +       con0 = readl_relaxed(con0_addr);
> +       con1 = readl_relaxed(con1_addr);
> +
> +       pll_en = con0 & PLL_BASE_EN;
> +
> +       /* set postdiv */
> +       con0 &= ~SDM_PLL_POSTDIV_MASK;
> +       con0 |= postdiv_idx << SDM_PLL_POSTDIV_L;
> +       writel_relaxed(con0, con0_addr);
> +
> +       /* set pcw */
> +       con1 &= ~SDM_PLL_PCW_MASK;
> +       con1 |= pcw << SDM_PLL_PCW_L;
> +
> +       if (pll_en)
> +               con1 |= PLL_PCW_CHG;
> +
> +       writel_relaxed(con1, con1_addr);
> +
> +       if (pll_en) {
> +               wmb();  /* sync write before delay */
> +               udelay(20);
> +       }
> +
> +       spin_unlock_irqrestore(pll->lock, flags);
> +}
> +
> +static int mtk_clk_sdm_pll_set_rate(
> +               struct clk_hw *hw,
> +               unsigned long rate,
> +               unsigned long parent_rate)
> +{
> +       u32 pcwfbits = 14;
> +       u32 pcw = 0;
> +       u32 postdiv_idx = 0;
> +       int r;
> +
> +       parent_rate = parent_rate ? parent_rate : 26000000;
> +       r = mtk_calc_pll_freq_cfg(&pcw, &postdiv_idx, rate,
> +                       parent_rate, pcwfbits);
> +
> +       if (r == 0)
> +               mtk_clk_sdm_pll_set_rate_regs(hw, pcw, postdiv_idx);
> +
> +       return r;
> +}
> +
> +const struct clk_ops mt8173_sdm_pll_ops = {
> +       .is_enabled     = mtk_clk_pll_is_enabled,
> +       .prepare        = mtk_clk_pll_prepare,
> +       .unprepare      = mtk_clk_pll_unprepare,
> +       .recalc_rate    = mtk_clk_sdm_pll_recalc_rate,
> +       .round_rate     = mtk_clk_pll_round_rate,
> +       .set_rate       = mtk_clk_sdm_pll_set_rate,
> +};
> +
> +#define ARM_PLL_POSTDIV_H      26
> +#define ARM_PLL_POSTDIV_L      24
> +#define ARM_PLL_POSTDIV_MASK   GENMASK(ARM_PLL_POSTDIV_H, ARM_PLL_POSTDIV_L)
> +#define ARM_PLL_PCW_H          20
> +#define ARM_PLL_PCW_L          0
> +#define ARM_PLL_PCW_MASK       GENMASK(ARM_PLL_PCW_H, ARM_PLL_PCW_L)
> +
> +static unsigned long mtk_clk_arm_pll_recalc_rate(
> +               struct clk_hw *hw,
> +               unsigned long parent_rate)
> +{
> +       struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
> +
> +       u32 con1 = readl_relaxed(pll->base_addr + 4);
> +
> +       u32 posdiv = (con1 & ARM_PLL_POSTDIV_MASK) >> ARM_PLL_POSTDIV_L;
> +       u32 pcw = (con1 & ARM_PLL_PCW_MASK) >> ARM_PLL_PCW_L;
> +       u32 pcwfbits = 14;
> +
> +       u32 vco_freq;
> +       unsigned long r;
> +
> +       parent_rate = parent_rate ? parent_rate : 26000000;
> +
> +       vco_freq = mtk_calc_pll_vco_freq(parent_rate, pcw, 1, 1, pcwfbits);
> +       r = (vco_freq + pll_posdiv_map[posdiv] - 1) / pll_posdiv_map[posdiv];
> +
> +       return r;
> +}
> +
> +static void mtk_clk_arm_pll_set_rate_regs(
> +               struct clk_hw *hw,
> +               u32 pcw,
> +               u32 postdiv_idx)
> +
> +{
> +       unsigned long flags = 0;

No need to initialize.

> +       struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
> +       void __iomem *con0_addr = pll->base_addr;
> +       void __iomem *con1_addr = pll->base_addr + 4;
> +       u32 con0;
> +       u32 con1;
> +       u32 pll_en;
> +
> +       spin_lock_irqsave(pll->lock, flags);
> +
> +       con0 = readl_relaxed(con0_addr);
> +       con1 = readl_relaxed(con1_addr);
> +
> +       pll_en = con0 & PLL_BASE_EN;
> +
> +       /* postdiv */
> +       con1 &= ~ARM_PLL_POSTDIV_MASK;
> +       con1 |= postdiv_idx << ARM_PLL_POSTDIV_L;
> +
> +       /* pcw */
> +       con1 &= ~ARM_PLL_PCW_MASK;
> +       con1 |= pcw << ARM_PLL_PCW_L;
> +
> +       if (pll_en)
> +               con1 |= PLL_PCW_CHG;
> +
> +       writel_relaxed(con1, con1_addr);
> +
> +       if (pll_en) {
> +               wmb();  /* sync write before delay */
> +               udelay(20);
> +       }
> +
> +       spin_unlock_irqrestore(pll->lock, flags);
> +}
> +
> +static int mtk_clk_arm_pll_set_rate(
> +               struct clk_hw *hw,
> +               unsigned long rate,
> +               unsigned long parent_rate)
> +{
> +       u32 pcwfbits = 14;
> +       u32 pcw = 0;
> +       u32 postdiv_idx = 0;
> +       int r;
> +
> +       parent_rate = parent_rate ? parent_rate : 26000000;
> +       r = mtk_calc_pll_freq_cfg(&pcw, &postdiv_idx, rate,
> +                       parent_rate, pcwfbits);
> +
> +       if (r == 0)
> +               mtk_clk_arm_pll_set_rate_regs(hw, pcw, postdiv_idx);
> +
> +       return r;
> +}
> +
> +const struct clk_ops mt8173_arm_pll_ops = {
> +       .is_enabled     = mtk_clk_pll_is_enabled,
> +       .prepare        = mtk_clk_pll_prepare,
> +       .unprepare      = mtk_clk_pll_unprepare,

Uhh, this is incorrect. If you provide prepare+unprepare, you also
need to provide is_prepared, not is_enabled. However, considering my
comments above, it should be possible to use enable+disable instead.

> +       .recalc_rate    = mtk_clk_arm_pll_recalc_rate,
> +       .round_rate     = mtk_clk_pll_round_rate,
> +       .set_rate       = mtk_clk_arm_pll_set_rate,
> +};
> +
> +static long mtk_clk_mm_pll_round_rate(
> +               struct clk_hw *hw,
> +               unsigned long rate,
> +               unsigned long *prate)
> +{
> +       u32 pcwfbits = 14;
> +       u32 pcw = 0;
> +       u32 postdiv = 0;
> +       u32 r;
> +
> +       if (rate <= 702000000)
> +               postdiv = 2;
> +
> +       *prate = *prate ? *prate : 26000000;

I feel like it wouldn't really be a bad idea to define all the numeric
constants as macros.

> +       rate = mtk_freq_limit(rate);
> +       mtk_calc_pll_freq_cfg(&pcw, &postdiv, rate, *prate, pcwfbits);
> +
> +       r = mtk_calc_pll_vco_freq(*prate, pcw, 1, 1, pcwfbits);
> +       r = (r + pll_posdiv_map[postdiv] - 1) / pll_posdiv_map[postdiv];
> +
> +       return r;
> +}
> +
> +static int mtk_clk_mm_pll_set_rate(
> +               struct clk_hw *hw,
> +               unsigned long rate,
> +               unsigned long parent_rate)
> +{
> +       u32 pcwfbits = 14;
> +       u32 pcw = 0;
> +       u32 postdiv_idx = 0;
> +       int r;
> +
> +       if (rate <= 702000000)
> +               postdiv_idx = 2;
> +
> +       parent_rate = parent_rate ? parent_rate : 26000000;
> +       r = mtk_calc_pll_freq_cfg(&pcw, &postdiv_idx, rate,
> +                       parent_rate, pcwfbits);
> +
> +       if (r == 0)
> +               mtk_clk_arm_pll_set_rate_regs(hw, pcw, postdiv_idx);
> +
> +       return r;
> +}
> +
> +const struct clk_ops mt8173_mm_pll_ops = {
> +       .is_enabled     = mtk_clk_pll_is_enabled,
> +       .prepare        = mtk_clk_pll_prepare,
> +       .unprepare      = mtk_clk_pll_unprepare,

Ditto.

> +       .recalc_rate    = mtk_clk_arm_pll_recalc_rate,
> +       .round_rate     = mtk_clk_mm_pll_round_rate,
> +       .set_rate       = mtk_clk_mm_pll_set_rate,
> +};
> +
> +static int mtk_clk_univ_pll_prepare(struct clk_hw *hw)
> +{
> +       unsigned long flags = 0;

No need to initialize.

> +       struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
> +       u32 r;
> +
> +       spin_lock_irqsave(pll->lock, flags);
> +
> +       r = readl_relaxed(pll->base_addr) | pll->en_mask;
> +       writel_relaxed(r, pll->base_addr);
> +       wmb();  /* sync write before delay */
> +       udelay(20);
> +
> +       if (pll->flags & HAVE_RST_BAR) {
> +               r = readl_relaxed(pll->base_addr) | RST_BAR_MASK;
> +               writel_relaxed(r, pll->base_addr);
> +       }
> +
> +       spin_unlock_irqrestore(pll->lock, flags);
> +
> +       return 0;
> +}
> +
> +static void mtk_clk_univ_pll_unprepare(struct clk_hw *hw)
> +{
> +       unsigned long flags = 0;

No need to initialize.

> +       struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
> +       u32 r;
> +
> +       if (pll->flags & PLL_AO)
> +               return;
> +
> +       spin_lock_irqsave(pll->lock, flags);
> +
> +       if (pll->flags & HAVE_RST_BAR) {
> +               r = readl_relaxed(pll->base_addr) & ~RST_BAR_MASK;
> +               writel_relaxed(r, pll->base_addr);
> +       }
> +
> +       r = readl_relaxed(pll->base_addr) & ~PLL_BASE_EN;
> +       writel_relaxed(r, pll->base_addr);
> +
> +       spin_unlock_irqrestore(pll->lock, flags);
> +}
> +
> +#define UNIV_PLL_POSTDIV_H     6
> +#define UNIV_PLL_POSTDIV_L     4
> +#define UNIV_PLL_POSTDIV_MASK  GENMASK(UNIV_PLL_POSTDIV_H, UNIV_PLL_POSTDIV_L)
> +#define UNIV_PLL_FBKDIV_H      20
> +#define UNIV_PLL_FBKDIV_L      14
> +#define UNIV_PLL_FBKDIV_MASK   GENMASK(UNIV_PLL_FBKDIV_H, UNIV_PLL_FBKDIV_L)
> +
> +static unsigned long mtk_clk_univ_pll_recalc_rate(
> +               struct clk_hw *hw,
> +               unsigned long parent_rate)
> +{
> +       struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
> +
> +       u32 con0 = readl_relaxed(pll->base_addr);
> +       u32 con1 = readl_relaxed(pll->base_addr + 4);
> +
> +       u32 fbkdiv = (con1 & UNIV_PLL_FBKDIV_MASK) >> UNIV_PLL_FBKDIV_L;
> +       u32 posdiv = (con0 & UNIV_PLL_POSTDIV_MASK) >> UNIV_PLL_POSTDIV_L;
> +
> +       u32 vco_freq;
> +       unsigned long r;
> +
> +       parent_rate = parent_rate ? parent_rate : 26000000;
> +
> +       vco_freq = parent_rate * fbkdiv;
> +       r = (vco_freq + pll_posdiv_map[posdiv] - 1) / pll_posdiv_map[posdiv];
> +
> +       return r;
> +}
> +
> +static void mtk_clk_univ_pll_set_rate_regs(
> +               struct clk_hw *hw,
> +               u32 pcw,
> +               u32 postdiv_idx)
> +{
> +       unsigned long flags = 0;

No need to initialize.

> +       struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
> +       void __iomem *con0_addr = pll->base_addr;
> +       void __iomem *con1_addr = pll->base_addr + 4;
> +       u32 con0;
> +       u32 con1;
> +       u32 pll_en;
> +
> +       spin_lock_irqsave(pll->lock, flags);
> +
> +       con0 = readl_relaxed(con0_addr);
> +       con1 = readl_relaxed(con1_addr);
> +
> +       pll_en = con0 & PLL_BASE_EN;
> +
> +       /* postdiv */
> +       con0 &= ~UNIV_PLL_POSTDIV_MASK;
> +       con0 |= postdiv_idx << UNIV_PLL_POSTDIV_L;
> +
> +       /* fkbdiv */
> +       con1 &= ~UNIV_PLL_FBKDIV_MASK;
> +       con1 |= pcw << UNIV_PLL_FBKDIV_L;
> +
> +       writel_relaxed(con0, con0_addr);
> +       writel_relaxed(con1, con1_addr);
> +
> +       if (pll_en) {
> +               wmb();  /* sync write before delay */

The comment should say why, not what, because you can easily see that
from the code (wmb() before udelay(20) obviously can't be anything
else than "sync write before delay").

> +               udelay(20);
> +       }
> +
> +       spin_unlock_irqrestore(pll->lock, flags);
> +}
> +
> +static long mtk_clk_univ_pll_round_rate(
> +               struct clk_hw *hw,
> +               unsigned long rate,
> +               unsigned long *prate)
> +{
> +       u32 pcwfbits = 0;
> +       u32 pcw = 0;
> +       u32 postdiv = 0;
> +       u32 r;
> +
> +       *prate = *prate ? *prate : 26000000;
> +       rate = mtk_freq_limit(rate);
> +       mtk_calc_pll_freq_cfg(&pcw, &postdiv, rate, *prate, pcwfbits);
> +
> +       r = *prate * pcw;
> +       r = (r + pll_posdiv_map[postdiv] - 1) / pll_posdiv_map[postdiv];
> +
> +       return r;
> +}
> +
> +static int mtk_clk_univ_pll_set_rate(
> +               struct clk_hw *hw,
> +               unsigned long rate,
> +               unsigned long parent_rate)
> +{
> +       u32 pcwfbits = 0;
> +       u32 pcw = 0;
> +       u32 postdiv_idx = 0;
> +       int r;
> +
> +       parent_rate = parent_rate ? parent_rate : 26000000;
> +       r = mtk_calc_pll_freq_cfg(&pcw, &postdiv_idx, rate,
> +                       parent_rate, pcwfbits);
> +
> +       if (r == 0)

I wonder if you shouldn't consider adding an error message to opposite case.

> +               mtk_clk_univ_pll_set_rate_regs(hw, pcw, postdiv_idx);
> +
> +       return r;
> +}
> +
> +const struct clk_ops mt8173_univ_pll_ops = {
> +       .is_enabled     = mtk_clk_pll_is_enabled,
> +       .prepare        = mtk_clk_univ_pll_prepare,
> +       .unprepare      = mtk_clk_univ_pll_unprepare,
> +       .recalc_rate    = mtk_clk_univ_pll_recalc_rate,
> +       .round_rate     = mtk_clk_univ_pll_round_rate,
> +       .set_rate       = mtk_clk_univ_pll_set_rate,
> +};
> +
> +static int mtk_clk_aud_pll_prepare(struct clk_hw *hw)
> +{
> +       unsigned long flags = 0;

No need to initialize.

> +       struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
> +       void __iomem *con0_addr = pll->base_addr;
> +       void __iomem *con2_addr = pll->base_addr + 8;

A macro for the offset would look better.

> +       u32 r;
> +
> +       spin_lock_irqsave(pll->lock, flags);
> +
> +       r = readl_relaxed(pll->pwr_addr) | PLL_PWR_ON;
> +       writel_relaxed(r, pll->pwr_addr);
> +       wmb();  /* sync write before delay */

Why? And couldn't you use writel() instead of writel_relaxed() + wmb()?

> +       udelay(1);
> +
> +       r = readl_relaxed(pll->pwr_addr) & ~PLL_ISO_EN;
> +       writel_relaxed(r, pll->pwr_addr);
> +       wmb();  /* sync write before delay */

Ditto.

> +       udelay(1);
> +
> +       r = readl_relaxed(con0_addr) | pll->en_mask;
> +       writel_relaxed(r, con0_addr);
> +
> +       r = readl_relaxed(con2_addr) | AUDPLL_TUNER_EN;
> +       writel_relaxed(r, con2_addr);
> +       wmb();  /* sync write before delay */

Ditto.

> +       udelay(20);
> +
> +       if (pll->flags & HAVE_RST_BAR) {
> +               r = readl_relaxed(con0_addr) | RST_BAR_MASK;
> +               writel_relaxed(r, con0_addr);
> +       }
> +
> +       spin_unlock_irqrestore(pll->lock, flags);
> +
> +       return 0;
> +}
> +
> +static void mtk_clk_aud_pll_unprepare(struct clk_hw *hw)
> +{
> +       unsigned long flags = 0;
> +       struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
> +       void __iomem *con0_addr = pll->base_addr;
> +       void __iomem *con2_addr = pll->base_addr + 8;
> +       u32 r;
> +
> +       if (pll->flags & PLL_AO)
> +               return;
> +
> +       spin_lock_irqsave(pll->lock, flags);
> +
> +       if (pll->flags & HAVE_RST_BAR) {
> +               r = readl_relaxed(con0_addr) & ~RST_BAR_MASK;
> +               writel_relaxed(r, con0_addr);
> +       }
> +
> +       r = readl_relaxed(con2_addr) & ~AUDPLL_TUNER_EN;
> +       writel_relaxed(r, con2_addr);
> +
> +       r = readl_relaxed(con0_addr) & ~PLL_BASE_EN;
> +       writel_relaxed(r, con0_addr);
> +
> +       r = readl_relaxed(pll->pwr_addr) | PLL_ISO_EN;
> +       writel_relaxed(r, pll->pwr_addr);
> +
> +       r = readl_relaxed(pll->pwr_addr) & ~PLL_PWR_ON;
> +       writel_relaxed(r, pll->pwr_addr);
> +
> +       spin_unlock_irqrestore(pll->lock, flags);
> +}
> +
> +#define AUD_PLL_POSTDIV_H      6
> +#define AUD_PLL_POSTDIV_L      4
> +#define AUD_PLL_POSTDIV_MASK   GENMASK(AUD_PLL_POSTDIV_H, AUD_PLL_POSTDIV_L)
> +#define AUD_PLL_PCW_H          30
> +#define AUD_PLL_PCW_L          0
> +#define AUD_PLL_PCW_MASK       GENMASK(AUD_PLL_PCW_H, AUD_PLL_PCW_L)
> +
> +static unsigned long mtk_clk_aud_pll_recalc_rate(
> +               struct clk_hw *hw,
> +               unsigned long parent_rate)
> +{
> +       struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
> +
> +       u32 con0 = readl_relaxed(pll->base_addr);
> +       u32 con1 = readl_relaxed(pll->base_addr + 4);
> +
> +       u32 posdiv = (con0 & AUD_PLL_POSTDIV_MASK) >> AUD_PLL_POSTDIV_L;
> +       u32 pcw = (con1 & AUD_PLL_PCW_MASK) >> AUD_PLL_PCW_L;
> +       u32 pcwfbits = 24;
> +
> +       u32 vco_freq;
> +       unsigned long r;
> +
> +       parent_rate = parent_rate ? parent_rate : 26000000;
> +
> +       vco_freq = mtk_calc_pll_vco_freq(parent_rate, pcw, 1, 1, pcwfbits);
> +       r = (vco_freq + pll_posdiv_map[posdiv] - 1) / pll_posdiv_map[posdiv];
> +
> +       return r;
> +}
> +
> +static void mtk_clk_aud_pll_set_rate_regs(
> +               struct clk_hw *hw,
> +               u32 pcw,
> +               u32 postdiv_idx)
> +{
> +       unsigned long flags = 0;
> +       struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
> +       void __iomem *con0_addr = pll->base_addr;
> +       void __iomem *con1_addr = pll->base_addr + 4;
> +       void __iomem *con2_addr = pll->base_addr + 8;
> +       u32 con0;
> +       u32 con1;
> +       u32 pll_en;
> +
> +       spin_lock_irqsave(pll->lock, flags);
> +
> +       con0 = readl_relaxed(con0_addr);
> +       con1 = readl_relaxed(con1_addr);
> +
> +       pll_en = con0 & PLL_BASE_EN;
> +
> +       /* set postdiv */
> +       con0 &= ~AUD_PLL_POSTDIV_MASK;
> +       con0 |= postdiv_idx << AUD_PLL_POSTDIV_L;
> +       writel_relaxed(con0, con0_addr);
> +
> +       /* set pcw */
> +       con1 &= ~AUD_PLL_PCW_MASK;
> +       con1 |= pcw << AUD_PLL_PCW_L;
> +
> +       if (pll_en)
> +               con1 |= PLL_PCW_CHG;
> +
> +       writel_relaxed(con1, con1_addr);
> +       writel_relaxed(con1 + 1, con2_addr);
> +
> +       if (pll_en) {
> +               wmb();  /* sync write before delay */

Same as above.

> +               udelay(20);
> +       }
> +
> +       spin_unlock_irqrestore(pll->lock, flags);
> +}
> +
> +static long mtk_clk_aud_pll_round_rate(
> +               struct clk_hw *hw,
> +               unsigned long rate,
> +               unsigned long *prate)
> +{
> +       u32 pcwfbits = 24;
> +       u32 pcw = 0;
> +       u32 postdiv = 0;
> +       u32 r;
> +
> +       *prate = *prate ? *prate : 26000000;
> +       rate = mtk_freq_limit(rate);
> +       mtk_calc_pll_freq_cfg(&pcw, &postdiv, rate, *prate, pcwfbits);
> +
> +       r = mtk_calc_pll_vco_freq(*prate, pcw, 1, 1, pcwfbits);
> +       r = (r + pll_posdiv_map[postdiv] - 1) / pll_posdiv_map[postdiv];
> +
> +       return r;
> +}
> +
> +static int mtk_clk_aud_pll_set_rate(
> +               struct clk_hw *hw,
> +               unsigned long rate,
> +               unsigned long parent_rate)
> +{
> +       u32 pcwfbits = 24;
> +       u32 pcw = 0;
> +       u32 postdiv_idx = 0;
> +       int r;
> +
> +       parent_rate = parent_rate ? parent_rate : 26000000;
> +       r = mtk_calc_pll_freq_cfg(&pcw, &postdiv_idx, rate,
> +                       parent_rate, pcwfbits);
> +
> +       if (r == 0)
> +               mtk_clk_aud_pll_set_rate_regs(hw, pcw, postdiv_idx);
> +
> +       return r;
> +}
> +
> +const struct clk_ops mt8173_aud_pll_ops = {
> +       .is_enabled     = mtk_clk_pll_is_enabled,
> +       .prepare        = mtk_clk_aud_pll_prepare,
> +       .unprepare      = mtk_clk_aud_pll_unprepare,
> +       .recalc_rate    = mtk_clk_aud_pll_recalc_rate,
> +       .round_rate     = mtk_clk_aud_pll_round_rate,
> +       .set_rate       = mtk_clk_aud_pll_set_rate,
> +};
> diff --git a/drivers/clk/mediatek/clk-mt8173-pll.h b/drivers/clk/mediatek/clk-mt8173-pll.h
> new file mode 100644
> index 0000000..663ab4b
> --- /dev/null
> +++ b/drivers/clk/mediatek/clk-mt8173-pll.h
> @@ -0,0 +1,14 @@
> +#ifndef __DRV_CLK_MT8173_PLL_H
> +#define __DRV_CLK_MT8173_PLL_H
> +
> +/*
> + * This is a private header file. DO NOT include it except clk-*.c.
> + */

I'd say this comment is redundant, because this file is already
private to mediatek clock code by how it is located in
drivers/clk/mediatek.

> +
> +extern const struct clk_ops mt8173_sdm_pll_ops;
> +extern const struct clk_ops mt8173_arm_pll_ops;
> +extern const struct clk_ops mt8173_mm_pll_ops;
> +extern const struct clk_ops mt8173_univ_pll_ops;
> +extern const struct clk_ops mt8173_aud_pll_ops;
> +
> +#endif /* __DRV_CLK_MT8173_PLL_H */
> diff --git a/drivers/clk/mediatek/clk-mt8173.c b/drivers/clk/mediatek/clk-mt8173.c
> new file mode 100644
> index 0000000..d75e591
> --- /dev/null
> +++ b/drivers/clk/mediatek/clk-mt8173.c
> @@ -0,0 +1,1035 @@
> +/*
> + * 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-pll.h"
> +#include "clk-gate.h"
> +#include "clk-mt8173-pll.h"
> +
> +#include <dt-bindings/clock/mt8173-clk.h>
> +
> +/* ROOT */
> +#define clk_null               "clk_null"
> +#define clk26m                 "clk26m"
> +#define clk32k                 "clk32k"

Hmm, what's this? What's the purpose of defining the same string, just
without the quotation marks?

Best regards,
Tomasz

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 02/13] clk: mediatek: Add initial common clock support for Mediatek SoCs.
  2015-02-13  7:41   ` Tomasz Figa
@ 2015-02-13 12:06     ` Sascha Hauer
  2015-02-13 13:22       ` Tomasz Figa
  0 siblings, 1 reply; 27+ messages in thread
From: Sascha Hauer @ 2015-02-13 12:06 UTC (permalink / raw)
  To: Tomasz Figa
  Cc: Matthias Brugger, James Liao, Mike Turquette,
	YH Chen (陳昱豪),
	linux-kernel, Henry Chen, Rob Herring, kernel,
	Yingjoe Chen (陳英洲),
	Eddie Huang, Lee Jones, linux-arm-kernel


Hi Tomasz,

> > +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);
> > +}
> 
> Instead of duplicating the ops, couldn't you add a flag or something
> to mtk_clk_gate struct and then act appropriately in the ops? Also,
> see below.

I prefer duplicating the ops. It makes the functions simpler without
ifs.

> > diff --git a/drivers/clk/mediatek/clk-gate.h b/drivers/clk/mediatek/clk-gate.h
> > new file mode 100644
> > index 0000000..a44dcbf
> > --- /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>
> 
> Might not be necessary, but maybe the other people (all or some of
> them) from signed-off-by should be added to this and other copyright
> statements?

I rather do not want to update these copyrights frequently. Otherwise we
would see a lot of patches with an extra hunk changing the copyrights.
I'm glad we left that behind and look at the git history instead.
The above is the original author. I don't want to remove him, but I also
do not want to add every other person who touched that file.

The other stuff will be fixed in the next round. Thanks for reviewing.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 02/13] clk: mediatek: Add initial common clock support for Mediatek SoCs.
  2015-02-13 12:06     ` Sascha Hauer
@ 2015-02-13 13:22       ` Tomasz Figa
  0 siblings, 0 replies; 27+ messages in thread
From: Tomasz Figa @ 2015-02-13 13:22 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: Matthias Brugger, James Liao, Mike Turquette,
	YH Chen (陳昱豪),
	linux-kernel, Henry Chen, Rob Herring, kernel,
	Yingjoe Chen (陳英洲),
	Eddie Huang, Lee Jones, linux-arm-kernel

Hi Sascha,

On Fri, Feb 13, 2015 at 9:06 PM, Sascha Hauer <s.hauer@pengutronix.de> wrote:
>
> Hi Tomasz,
>
>> > +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);
>> > +}
>>
>> Instead of duplicating the ops, couldn't you add a flag or something
>> to mtk_clk_gate struct and then act appropriately in the ops? Also,
>> see below.
>
> I prefer duplicating the ops. It makes the functions simpler without
> ifs.

I meant something else. Compared to ifs I'd prefer duplicated ops too.

is_enabled()
{
    status = regmap_read() ^ (inverted << shift);
    return status & BIT(shift);
}

However I missed the fact that writing uses set and clear registers,
which effectively means that this approach can't really be used for
writing, so I'm okay with keeping this as is.

>
>> > diff --git a/drivers/clk/mediatek/clk-gate.h b/drivers/clk/mediatek/clk-gate.h
>> > new file mode 100644
>> > index 0000000..a44dcbf
>> > --- /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>
>>
>> Might not be necessary, but maybe the other people (all or some of
>> them) from signed-off-by should be added to this and other copyright
>> statements?
>
> I rather do not want to update these copyrights frequently. Otherwise we
> would see a lot of patches with an extra hunk changing the copyrights.
> I'm glad we left that behind and look at the git history instead.
> The above is the original author. I don't want to remove him, but I also
> do not want to add every other person who touched that file.

Alright. I just wanted to make sure that this is desired state.

>
> The other stuff will be fixed in the next round. Thanks for reviewing.

You're welcome. Looking forward for next revision.

Best regards,
Tomasz

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 13/13] mfd: Add support for the MediaTek MT6397 PMIC
  2015-02-09 10:47 ` [PATCH 13/13] mfd: Add support " Sascha Hauer
@ 2015-02-16  9:56   ` Lee Jones
       [not found]     ` <20150218181904.421.59675@quantum>
  0 siblings, 1 reply; 27+ messages in thread
From: Lee Jones @ 2015-02-16  9:56 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: Matthias Brugger, linux-arm-kernel, linux-kernel, Rob Herring,
	Eddie Huang, Yingjoe Chen (陳英洲),
	Henry Chen, YH Chen (陳昱豪),
	kernel, Mike Turquette, Flora Fu, Samuel Ortiz

> From: Flora Fu <flora.fu@mediatek.com>
> 
> This adds support for the MediaTek MT6397 PMIC. This is a
> multifunction device with the following sub modules:
> 
> - Regulator
> - RTC
> - Audio codec
> - GPIO
> - Clock
> 
> It is interfaced to the host controller using SPI interface by a proprietary
> hardware called PMIC wrapper or pwrap. MT6397 MFD is a child device of the
> pwrap.
> 
> Signed-off-by: Flora Fu, MediaTek
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> Cc: Samuel Ortiz <sameo@linux.intel.com>
> Cc: Lee Jones <lee.jones@linaro.org>
> ---
>  drivers/mfd/Kconfig                  |  10 +
>  drivers/mfd/Makefile                 |   1 +
>  drivers/mfd/mt6397-core.c            | 223 +++++++++++++++++++++
>  include/linux/mfd/mt6397/core.h      |  64 +++++++
>  include/linux/mfd/mt6397/registers.h | 362 +++++++++++++++++++++++++++++++++++
>  5 files changed, 660 insertions(+)
>  create mode 100644 drivers/mfd/mt6397-core.c
>  create mode 100644 include/linux/mfd/mt6397/core.h
>  create mode 100644 include/linux/mfd/mt6397/registers.h

Looks okay to me now.

Acked-by: Lee Jones <lee.jones@linaro.org>

What's the merge plan for this set?

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 06/13] clk: mediatek: Add basic clocks for Mediatek MT8173.
  2015-02-13  9:56   ` Tomasz Figa
@ 2015-02-19  8:24     ` Sascha Hauer
  0 siblings, 0 replies; 27+ messages in thread
From: Sascha Hauer @ 2015-02-19  8:24 UTC (permalink / raw)
  To: Tomasz Figa
  Cc: Matthias Brugger, James Liao, Mike Turquette,
	YH Chen (陳昱豪),
	linux-kernel, Henry Chen, Rob Herring, kernel,
	Yingjoe Chen (陳英洲),
	Eddie Huang, Lee Jones, linux-arm-kernel

On Fri, Feb 13, 2015 at 06:56:53PM +0900, Tomasz Figa wrote:
> Please find my comments inline.
> 
> On Mon, Feb 9, 2015 at 7:47 PM, Sascha Hauer <s.hauer@pengutronix.de> wrote:
> > From: James Liao <jamesjj.liao@mediatek.com>
> >
> > 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-pll.c |  807 +++++++++++++++++++++++++
> >  drivers/clk/mediatek/clk-mt8173-pll.h |   14 +
> >  drivers/clk/mediatek/clk-mt8173.c     | 1035 +++++++++++++++++++++++++++++++++
> >  4 files changed, 1857 insertions(+)
> >  create mode 100644 drivers/clk/mediatek/clk-mt8173-pll.c
> >  create mode 100644 drivers/clk/mediatek/clk-mt8173-pll.h
> >  create mode 100644 drivers/clk/mediatek/clk-mt8173.c
> >
> > diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile
> > index afb52e5..e030416 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 clk-mt8135-pll.o
> > +obj-y += clk-mt8173.o clk-mt8173-pll.o
> > diff --git a/drivers/clk/mediatek/clk-mt8173-pll.c b/drivers/clk/mediatek/clk-mt8173-pll.c
> > new file mode 100644
> > index 0000000..9f6f821
> > --- /dev/null
> > +++ b/drivers/clk/mediatek/clk-mt8173-pll.c
> > @@ -0,0 +1,807 @@
> > +/*
> > + * 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/io.h>
> > +#include <linux/slab.h>
> > +#include <linux/delay.h>
> > +#include <linux/clkdev.h>
> > +
> > +#include "clk-mtk.h"
> > +#include "clk-pll.h"
> > +#include "clk-mt8173-pll.h"
> > +
> > +#define PLL_BASE_EN    BIT(0)
> > +#define PLL_PWR_ON     BIT(0)
> > +#define PLL_ISO_EN     BIT(1)
> > +#define PLL_PCW_CHG    BIT(31)
> > +#define RST_BAR_MASK   BIT(24)
> > +#define AUDPLL_TUNER_EN        BIT(31)
> > +
> > +static const u32 pll_posdiv_map[8] = { 1, 2, 4, 8, 16, 16, 16, 16 };
> 
> It might be nice to have a comment what this array is for and how the
> values were calculated.

It's the table for a power of two divider. This can be calculated, no
need for a table.

> 
> > +
> > +static u32 mtk_calc_pll_vco_freq(
> > +               u32 fin,
> > +               u32 pcw,
> > +               u32 vcodivsel,
> > +               u32 prediv,
> > +               u32 pcwfbits)
> > +{
> > +       /* vco = (fin * pcw * vcodivsel / prediv) >> pcwfbits; */
> > +       u64 vco = fin;
> > +       u8 c = 0;
> > +
> > +       vco = vco * pcw * vcodivsel;
> 
> Could you use here (u64)fin directly for increased readability and
> drop the initialization of vco?

yes

> 
> > +       do_div(vco, prediv);
> > +
> > +       if (vco & GENMASK(pcwfbits - 1, 0))
> > +               c = 1;
> 
> What is c? Could the variable has a more meaningful name?

I have no idea. This is not explained in the datasheet.

> 
> > +
> > +       vco >>= pcwfbits;
> > +
> > +       if (c)
> > +               ++vco;
> > +
> > +       return (u32)vco;
> > +}
> > +
> > +static u32 mtk_freq_limit(u32 freq)
> > +{
> > +       static const u64 freq_max = 3000UL * 1000 * 1000;       /* 3000 MHz */
> 
> 3 GHz probably? Could you define (if not defined somewhere already) a
> macro for GHZ and write this as 3 * GHZ?

Did that.

> 
> > +       static const u32 freq_min = 1000 * 1000 * 1000 / 16;    /* 62.5 MHz */
> 
> Why don't you write it as 62500 * KHZ or 62 * MHZ + 500 * KHZ?
> 
> > +
> > +       if (freq <= freq_min)
> > +               freq = freq_min + 16;
> 
> Could you explain what's happening here? Where does the 16 come from
> and why it is not defined as a macro?

I don't know what's going on here. What I find suspicious is that when
freq is between freq_min and freq_min + 16 it is not changed. I just
dropped this. Whoever thinks he needs this can probably explain what
it's good for.

> 
> > +       else if (freq > freq_max)
> > +               freq = freq_max;
> > +
> > +       return freq;
> > +}
> > +
> > +static int mtk_calc_pll_freq_cfg(
> > +               u32 *pcw,
> > +               u32 *postdiv_idx,
> > +               u32 freq,
> > +               u32 fin,
> > +               int pcwfbits)
> > +{
> > +       static const u64 freq_max = 3000UL * 1000 * 1000;       /* 3000 MHz */
> > +       static const u64 freq_min = 1000 * 1000 * 1000;         /* 1000 MHz */
> > +       static const u64 postdiv[] = { 1, 2, 4, 8, 16 };
> > +       u64 n_info;
> > +       u32 idx;
> > +
> > +       /* search suitable postdiv */
> > +       for (idx = *postdiv_idx;
> > +               idx < ARRAY_SIZE(postdiv) && postdiv[idx] * freq <= freq_min;
> > +               idx++)
> > +               ;
> 
> Please document the arguments of this function. It is not obvious why
> the value at postdiv_idx is used as starting point, even though this
> pointer is also used to store the output value...

It seems it is used by some callers to ensure a minimum divider.

> 
> > +
> > +       if (idx >= ARRAY_SIZE(postdiv))
> > +               return -EINVAL; /* freq is out of range (too low) */
> > +       else if (postdiv[idx] * freq > freq_max)
> > +               return -EINVAL; /* freq is out of range (too high) */
> > +
> > +       /* n_info = freq * postdiv / 26MHz * 2^pcwfbits */
> > +       n_info = (postdiv[idx] * freq) << pcwfbits;
> > +       do_div(n_info, fin);
> > +
> > +       *postdiv_idx = idx;
> > +       *pcw = (u32)n_info;
> > +
> > +       return 0;
> > +}
> > +
> > +static int mtk_clk_pll_is_enabled(struct clk_hw *hw)
> > +{
> > +       struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
> > +
> > +       return (readl_relaxed(pll->base_addr) & PLL_BASE_EN) != 0;
> > +}
> > +
> > +static int mtk_clk_pll_prepare(struct clk_hw *hw)
> 
> Hmm, contents of this function don't seem to sleep. Maybe this should
> be enable instead of prepare?

Hm, I think I rather use usleep_range instead of udelay and keep it in
the prepare/unprepare path. I don't think there's need to enable/disable
the PLLs in the hot pathes.

> > +const struct clk_ops mt8173_arm_pll_ops = {
> > +       .is_enabled     = mtk_clk_pll_is_enabled,
> > +       .prepare        = mtk_clk_pll_prepare,
> > +       .unprepare      = mtk_clk_pll_unprepare,
> 
> Uhh, this is incorrect. If you provide prepare+unprepare, you also
> need to provide is_prepared, not is_enabled. However, considering my
> comments above, it should be possible to use enable+disable instead.

I will decide for one of both.

> 
> > +       .recalc_rate    = mtk_clk_arm_pll_recalc_rate,
> > +       .round_rate     = mtk_clk_pll_round_rate,
> > +       .set_rate       = mtk_clk_arm_pll_set_rate,
> > +};
> > +
> > +static long mtk_clk_mm_pll_round_rate(
> > +               struct clk_hw *hw,
> > +               unsigned long rate,
> > +               unsigned long *prate)
> > +{
> > +       u32 pcwfbits = 14;
> > +       u32 pcw = 0;
> > +       u32 postdiv = 0;
> > +       u32 r;
> > +
> > +       if (rate <= 702000000)
> > +               postdiv = 2;
> > +
> > +       *prate = *prate ? *prate : 26000000;
> 
> I feel like it wouldn't really be a bad idea to define all the numeric
> constants as macros.

The above is unnecessary. The clk framework will never call us with
prate == NULL.

> > +       /* postdiv */
> > +       con0 &= ~UNIV_PLL_POSTDIV_MASK;
> > +       con0 |= postdiv_idx << UNIV_PLL_POSTDIV_L;
> > +
> > +       /* fkbdiv */
> > +       con1 &= ~UNIV_PLL_FBKDIV_MASK;
> > +       con1 |= pcw << UNIV_PLL_FBKDIV_L;
> > +
> > +       writel_relaxed(con0, con0_addr);
> > +       writel_relaxed(con1, con1_addr);
> > +
> > +       if (pll_en) {
> > +               wmb();  /* sync write before delay */
> 
> The comment should say why, not what, because you can easily see that
> from the code (wmb() before udelay(20) obviously can't be anything
> else than "sync write before delay").

I'll drop the comment.

> > +       parent_rate = parent_rate ? parent_rate : 26000000;
> > +       r = mtk_calc_pll_freq_cfg(&pcw, &postdiv_idx, rate,
> > +                       parent_rate, pcwfbits);
> > +
> > +       if (r == 0)
> 
> I wonder if you shouldn't consider adding an error message to opposite case.

I'l refactor this so that mtk_calc_pll_freq_cfg() can't fail. This won't
be necessary anymore.

> > +static int mtk_clk_aud_pll_prepare(struct clk_hw *hw)
> > +{
> > +       unsigned long flags = 0;
> 
> No need to initialize.
> 
> > +       struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
> > +       void __iomem *con0_addr = pll->base_addr;
> > +       void __iomem *con2_addr = pll->base_addr + 8;
> 
> A macro for the offset would look better.
> 
> > +       u32 r;
> > +
> > +       spin_lock_irqsave(pll->lock, flags);
> > +
> > +       r = readl_relaxed(pll->pwr_addr) | PLL_PWR_ON;
> > +       writel_relaxed(r, pll->pwr_addr);
> > +       wmb();  /* sync write before delay */
> 
> Why? And couldn't you use writel() instead of writel_relaxed() + wmb()?

The original author claims this is needed. I can't prove the opposite,
so I kept it.

Anyway, it seems that writel() is writel_relaxed() + a wmb(), so I'll
change it.

> > +#include <dt-bindings/clock/mt8173-clk.h>
> > +
> > +/* ROOT */
> > +#define clk_null               "clk_null"
> > +#define clk26m                 "clk26m"
> > +#define clk32k                 "clk32k"
> 
> Hmm, what's this? What's the purpose of defining the same string, just
> without the quotation marks?

I think the intention was to let the compiler detect typos when using
the same strings multiple times. I don't like this either, will drop.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 13/13] mfd: Add support for the MediaTek MT6397 PMIC
       [not found]             ` <20150219121304.GH12212@x1>
@ 2015-02-19 21:41               ` Mike Turquette
  0 siblings, 0 replies; 27+ messages in thread
From: Mike Turquette @ 2015-02-19 21:41 UTC (permalink / raw)
  To: Lee Jones, Sascha Hauer
  Cc: Matthias Brugger, linux-arm-kernel, linux-kernel, Rob Herring,
	Eddie Huang, "Yingjoe Chen (陳英洲),
	Henry Chen, "YH Chen (陳昱豪),
	kernel, Flora Fu, Samuel Ortiz

Quoting Lee Jones (2015-02-19 04:13:04)
> On Thu, 19 Feb 2015, Sascha Hauer wrote:
> 
> > On Thu, Feb 19, 2015 at 08:43:49AM +0000, Lee Jones wrote:
> > > On Thu, 19 Feb 2015, Sascha Hauer wrote:
> > > 
> > > > > > Looks okay to me now.
> > > > > > 
> > > > > > Acked-by: Lee Jones <lee.jones@linaro.org>
> > > > > > 
> > > > > > What's the merge plan for this set?
> > > > > 
> > > > > Patches 1-9 are clock related an several of them have review comments
> > > > > that need to be addressed. I wonder if a V2 series can break out the
> > > > > various subsystems bits from each other?
> > > > 
> > > > I'll send a new series later this day. These used to be two series, but
> > > > the PMIC wrapper patches depend on the clock and reset controllers, also
> > > > the device nodes depend on the clock/reset defines from the clock
> > > > support patches. What do you suggest? In the early days of a SoC
> > > > everything seems to depend on everything.
> > > 
> > > Only build dependencies count.  So long as the Kconfigs are setup
> > > correct, there shouldn't be any issue in taking patches in one
> > > subsystem at a time.
> > 
> > The dts snippets need the files in include/dt-bindings, so indeed this
> > is a build dependency. However, this comes only in with the dts changes.
> > 
> > So here's the plan:
> > 
> > - Mike takes the clk patches
> > - Matthias takes the pmic wrapper driver (in drivers/soc/mediatek/)
> > - You take the MT6397 core driver.
> 
> Sounds reasonable.  Just ensure that each set is orthogonal and builds
> (or doesn't attempt to) and we'll be in a good place.

Agreed.

Regards,
Mike

> 
> > I'll queue up the dts changes locally and ask Arnd to take these after
> > next -rc1 so that all dependencies are in. Unfortunately this means that
> > the patches can't be tested until everything is together after next
> > -rc1.
> 
> I'm sure you will be diligent enough to test the interoperability of
> the sets combined.  Failing that we can deal with any unavoidable
> fall-out during the -rcs.
> 
> -- 
> Lee Jones
> Linaro STMicroelectronics Landing Team Lead
> Linaro.org │ Open source software for ARM SoCs
> Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 27+ messages in thread

end of thread, other threads:[~2015-02-19 21:42 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-02-09 10:47 [PATCH v5]: clk: Add common clock support for Mediatek MT8135 and MT8173 Sascha Hauer
2015-02-09 10:47 ` [PATCH 01/13] clk: dts: mediatek: add Mediatek MT8135 clock bindings Sascha Hauer
2015-02-09 13:35   ` Philipp Zabel
2015-02-09 10:47 ` [PATCH 02/13] clk: mediatek: Add initial common clock support for Mediatek SoCs Sascha Hauer
2015-02-13  7:41   ` Tomasz Figa
2015-02-13 12:06     ` Sascha Hauer
2015-02-13 13:22       ` Tomasz Figa
2015-02-09 10:47 ` [PATCH 03/13] clk: mediatek: Add reset controller support Sascha Hauer
2015-02-09 13:35   ` Philipp Zabel
2015-02-09 10:47 ` [PATCH 04/13] clk: mediatek: Add basic clocks for Mediatek MT8135 Sascha Hauer
2015-02-09 10:47 ` [PATCH 05/13] clk: dts: mediatek: add Mediatek MT8173 clock bindings Sascha Hauer
2015-02-09 10:47 ` [PATCH 06/13] clk: mediatek: Add basic clocks for Mediatek MT8173 Sascha Hauer
2015-02-13  9:56   ` Tomasz Figa
2015-02-19  8:24     ` Sascha Hauer
2015-02-09 10:47 ` [PATCH 07/13] dt: bindings: Add MediaTek MT8135/MT8173 reset controller defines Sascha Hauer
2015-02-09 10:47 ` [PATCH 08/13] soc: mediatek: Add PMIC wrapper for MT8135 and MT6397 SoC Sascha Hauer
2015-02-09 10:47 ` [PATCH 09/13] ARM: dts: mediatek: Enable clock support for Mediatek MT8135 Sascha Hauer
2015-02-09 10:51   ` Russell King - ARM Linux
2015-02-09 11:25     ` Sascha Hauer
2015-02-09 11:27       ` Russell King - ARM Linux
2015-02-09 11:44         ` Sascha Hauer
2015-02-09 10:47 ` [PATCH 10/13] ARM: dts: mt8135: Add pmic wrapper nodes Sascha Hauer
2015-02-09 10:47 ` [PATCH 11/13] ARM: dts: mt8135-evbp1: Add PMIC support Sascha Hauer
2015-02-09 10:47 ` [PATCH 12/13] mfd: dt-bindings: Add bindings for the MediaTek MT6397 PMIC Sascha Hauer
2015-02-09 10:47 ` [PATCH 13/13] mfd: Add support " Sascha Hauer
2015-02-16  9:56   ` Lee Jones
     [not found]     ` <20150218181904.421.59675@quantum>
     [not found]       ` <20150219082655.GV12209@pengutronix.de>
     [not found]         ` <20150219084349.GA12212@x1>
     [not found]           ` <20150219120409.GW12209@pengutronix.de>
     [not found]             ` <20150219121304.GH12212@x1>
2015-02-19 21:41               ` Mike Turquette

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).