[PATCH 07/22] msm: clock: Refactor clock-7x30 into generic clock-local driver

Stephen Boyd
2010-12-17T00:53:13Z

From: Matt Wagantall <mattw@codeaurora.org>

The generic 'clock-local' driver is introduced to facilitate
sharing of common code among local clock drivers for different
SoCs. Presently, only 7x30 makes use of this driver.

SoC-independent code is implemented in clock-local.c, while
SoC-specific code is implemented in other clock-* files (ex.
clock-7x30.c).

Reviewed-by: Saravana Kannan <skannan@codeaurora.org>
Signed-off-by: Matt Wagantall <mattw@codeaurora.org>
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
---
arch/arm/mach-msm/Makefile | 1 +
arch/arm/mach-msm/clock-7x30.c | 1462 +++++++++++++--------------------------
arch/arm/mach-msm/clock-7x30.h | 230 +++----
arch/arm/mach-msm/clock-local.c | 679 ++++++++++++++++++
arch/arm/mach-msm/clock-local.h | 232 +++++++
5 files changed, 1516 insertions(+), 1088 deletions(-)
create mode 100644 arch/arm/mach-msm/clock-local.c
create mode 100644 arch/arm/mach-msm/clock-local.h

diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 8588b57..33f0c39 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -2,6 +2,7 @@ obj-y += io.o idle.o timer.o
ifdef CONFIG_MSM_PROC_COMM
obj-$(CONFIG_DEBUG_FS) += clock-debug.o
endif
+obj-$(CONFIG_ARCH_MSM7X30) += clock-local.o
obj-$(CONFIG_ARCH_MSM7X30) += clock-7x30.o
ifndef CONFIG_ARCH_MSM8X60
obj-y += acpuclock-arm11.o
diff --git a/arch/arm/mach-msm/clock-7x30.c b/arch/arm/mach-msm/clock-7x30.c
index beca3a6..0637bee 100644
--- a/arch/arm/mach-msm/clock-7x30.c
+++ b/arch/arm/mach-msm/clock-7x30.c
@@ -29,16 +29,13 @@
#include <mach/clk.h>

#include "clock.h"
+#include "clock-local.h"
#include "clock-7x30.h"
#include "clock-pcom.h"
#include "proc_comm.h"

-#define REG_BASE(off) (MSM_CLK_CTL_BASE + off)
-#define REG(off) (MSM_CLK_CTL_SH2_BASE + off)
-#define MNCNTR_EN_MASK B(8)
-#define MNCNTR_RST_MASK B(7)
-#define MNCNTR_MODE_MASK BM(6, 5)
-#define MNCNTR_MODE BVAL(6, 5, 0x2) /* Dual-edge mode. */
+#define REG_BASE(off) (MSM_CLK_CTL_BASE + (off))
+#define REG(off) (MSM_CLK_CTL_SH2_BASE + (off))

/* Shadow-region 2 (SH2) registers. */
#define QUP_I2C_NS_REG REG(0x04F0)
@@ -106,1142 +103,597 @@
#define SH2_OWN_ROW1_BASE_REG REG_BASE(0x041C)
#define SH2_OWN_ROW2_BASE_REG REG_BASE(0x0424)

-struct clk_freq_tbl {
- uint32_t freq_hz;
- uint32_t src;
- uint32_t md_val;
- uint32_t ns_val;
- uint32_t mode;
- unsigned msmc1;
-};
-
-struct clk_local {
- uint32_t count;
- uint32_t type;
- void __iomem *md_reg;
- void __iomem *ns_reg;
- uint32_t freq_mask;
- uint32_t br_en_mask;
- uint32_t root_en_mask;
- int parent;
- uint32_t *children;
- const struct clk_freq_tbl *freq_tbl;
- const struct clk_freq_tbl *current_freq;
- void __iomem *halt_reg;
- uint32_t halt_mask;
- uint32_t test_vector;
-};
-
-
-enum {
- SRC_PLL0 = 4, /* Modem PLL */
- SRC_PLL1 = 1, /* Global PLL */
- SRC_PLL3 = 3, /* Multimedia/Peripheral PLL or Backup PLL1 */
- SRC_PLL4 = 2, /* Display PLL */
- SRC_LPXO = 6, /* Low power XO. */
- SRC_TCXO = 0, /* Used for sources that always source from tcxo */
- SRC_AXI = 100, /* Used for rates that sync to AXI */
- SRC_NONE /* Used for sources that can't be turned on/off. */
-};
-
-static uint32_t src_pll_tbl[] = {
- [SRC_PLL0] = PLL_0,
- [SRC_PLL1] = PLL_1,
- [SRC_PLL3] = PLL_3,
- [SRC_PLL4] = PLL_4,
-};
-
-#define B(x) BIT(x)
-#define BM(msb, lsb) (((((uint32_t)-1) << (31-msb)) >> (31-msb+lsb)) << lsb)
-#define BVAL(msb, lsb, val) (((val) << lsb) & BM(msb, lsb))

+/* MUX source input identifiers. */
+#define SRC_SEL_PLL0 4 /* Modem PLL */
+#define SRC_SEL_PLL1 1 /* Global PLL */
+#define SRC_SEL_PLL3 3 /* Multimedia/Peripheral PLL or Backup PLL1 */
+#define SRC_SEL_PLL4 2 /* Display PLL */
+#define SRC_SEL_LPXO 6 /* Low-power XO */
+#define SRC_SEL_TCXO 0 /* Used for sources that always source from TCXO */
+#define SRC_SEL_AXI 0 /* Used for rates that sync to AXI */
+
+/* Source name to PLL mappings. */
+#define SRC_PLL0 PLL_0
+#define SRC_PLL1 PLL_1
+#define SRC_PLL3 PLL_3
+#define SRC_PLL4 PLL_4
+#define SRC_LPXO LPXO
+#define SRC_TCXO TCXO
+#define SRC_AXI AXI
+
+/* Clock declaration macros. */
+#define MN_MODE_DUAL_EDGE 0x2
#define MD8(m, n) (BVAL(15, 8, m) | BVAL(7, 0, ~(n)))
-#define N8(msb, lsb, m, n) (BVAL(msb, lsb, ~(n-m)))
+#define N8(msb, lsb, m, n) (BVAL(msb, lsb, ~(n-m)) | BVAL(6, 5, \
+ (MN_MODE_DUAL_EDGE * !!(n))))
#define MD16(m, n) (BVAL(31, 16, m) | BVAL(15, 0, ~(n)))
-#define N16(m, n) (BVAL(31, 16, ~(n-m)))
+#define N16(m, n) (BVAL(31, 16, ~(n-m)) | BVAL(6, 5, \
+ (MN_MODE_DUAL_EDGE * !!(n))))
#define SPDIV(s, d) (BVAL(4, 3, d-1) | BVAL(2, 0, s))
#define SDIV(s, d) (BVAL(6, 3, d-1) | BVAL(2, 0, s))
#define F_MASK_BASIC (BM(6, 3)|BM(2, 0))
-#define F_MASK_MND16 (BM(31, 16)|BM(4, 3)|BM(2, 0))
-#define F_MASK_MND8(m, l) (BM(m, l)|BM(4, 3)|BM(2, 0))
-
-#define F_RAW(f, s, m_v, n_v, mde, v) { \
- .freq_hz = f, \
- .src = s, \
- .md_val = m_v, \
- .ns_val = n_v, \
- .mode = mde, \
- .msmc1 = v \
- }
+#define F_MASK_MND16 (BM(31, 16)|BM(6, 5)|BM(4, 3)|BM(2, 0))
+#define F_MASK_MND8(m, l) (BM(m, l)|BM(6, 5)|BM(4, 3)|BM(2, 0))

-#define FREQ_END 0
-#define F_BASIC(f, s, div, v) F_RAW(f, s, 0, SDIV(s, div), 0, v)
+/*
+ * Clock frequency definitions and macros
+ */
+#define F_BASIC(f, s, div, v) \
+ F_RAW(f, SRC_##s, 0, SDIV(SRC_SEL_##s, div), 0, 0, v, NULL)
#define F_MND16(f, s, div, m, n, v) \
- F_RAW(f, s, MD16(m, n), N16(m, n)|SPDIV(s, div), !!(n), v)
+ F_RAW(f, SRC_##s, MD16(m, n), N16(m, n)|SPDIV(SRC_SEL_##s, div), \
+ 0, (B(8) * !!(n)), v, NULL)
#define F_MND8(f, nmsb, nlsb, s, div, m, n, v) \
- F_RAW(f, s, MD8(m, n), N8(nmsb, nlsb, m, n)|SPDIV(s, div), !!(n), v)
-#define F_END F_RAW(FREQ_END, SRC_NONE, 0, 0, 0, MSMC1_END)
-
-static const struct clk_freq_tbl clk_tbl_csi[] = {
- F_MND8(153600000, 24, 17, SRC_PLL1, 2, 2, 5, NOMINAL),
- F_MND8(192000000, 24, 17, SRC_PLL1, 4, 0, 0, NOMINAL),
- F_MND8(384000000, 24, 17, SRC_PLL1, 2, 0, 0, NOMINAL),
+ F_RAW(f, SRC_##s, MD8(m, n), \
+ N8(nmsb, nlsb, m, n)|SPDIV(SRC_SEL_##s, div), 0, \
+ (B(8) * !!(n)), v, NULL)
+
+static struct clk_freq_tbl clk_tbl_csi[] = {
+ F_MND8(153600000, 24, 17, PLL1, 2, 2, 5, NOMINAL),
+ F_MND8(192000000, 24, 17, PLL1, 4, 0, 0, NOMINAL),
+ F_MND8(384000000, 24, 17, PLL1, 2, 0, 0, NOMINAL),
F_END,
};

-static const struct clk_freq_tbl clk_tbl_tcxo[] = {
- F_RAW(19200000, SRC_TCXO, 0, 0, 0, NOMINAL),
+static struct clk_freq_tbl clk_tbl_tcxo[] = {
+ F_RAW(19200000, SRC_TCXO, 0, 0, 0, 0, NOMINAL, NULL),
F_END,
};

-static const struct clk_freq_tbl clk_tbl_axi[] = {
- F_RAW(1, SRC_AXI, 0, 0, 0, NOMINAL),
+static struct clk_freq_tbl clk_tbl_axi[] = {
+ F_RAW(1, SRC_AXI, 0, 0, 0, 0, NOMINAL, NULL),
F_END,
};

-static const struct clk_freq_tbl clk_tbl_uartdm[] = {
- F_MND16( 3686400, SRC_PLL3, 3, 3, 200, NOMINAL),
- F_MND16( 7372800, SRC_PLL3, 3, 3, 100, NOMINAL),
- F_MND16(14745600, SRC_PLL3, 3, 3, 50, NOMINAL),
- F_MND16(32000000, SRC_PLL3, 3, 25, 192, NOMINAL),
- F_MND16(40000000, SRC_PLL3, 3, 125, 768, NOMINAL),
- F_MND16(46400000, SRC_PLL3, 3, 145, 768, NOMINAL),
- F_MND16(48000000, SRC_PLL3, 3, 25, 128, NOMINAL),
- F_MND16(51200000, SRC_PLL3, 3, 5, 24, NOMINAL),
- F_MND16(56000000, SRC_PLL3, 3, 175, 768, NOMINAL),
- F_MND16(58982400, SRC_PLL3, 3, 6, 25, NOMINAL),
- F_MND16(64000000, SRC_PLL1, 4, 1, 3, NOMINAL),
+static struct clk_freq_tbl clk_tbl_uartdm[] = {
+ F_MND16( 3686400, PLL3, 3, 3, 200, NOMINAL),
+ F_MND16( 7372800, PLL3, 3, 3, 100, NOMINAL),
+ F_MND16(14745600, PLL3, 3, 3, 50, NOMINAL),
+ F_MND16(32000000, PLL3, 3, 25, 192, NOMINAL),
+ F_MND16(40000000, PLL3, 3, 125, 768, NOMINAL),
+ F_MND16(46400000, PLL3, 3, 145, 768, NOMINAL),
+ F_MND16(48000000, PLL3, 3, 25, 128, NOMINAL),
+ F_MND16(51200000, PLL3, 3, 5, 24, NOMINAL),
+ F_MND16(56000000, PLL3, 3, 175, 768, NOMINAL),
+ F_MND16(58982400, PLL3, 3, 6, 25, NOMINAL),
+ F_MND16(64000000, PLL1, 4, 1, 3, NOMINAL),
F_END,
};

-static const struct clk_freq_tbl clk_tbl_mdh[] = {
- F_BASIC( 49150000, SRC_PLL3, 15, NOMINAL),
- F_BASIC( 92160000, SRC_PLL3, 8, NOMINAL),
- F_BASIC(122880000, SRC_PLL3, 6, NOMINAL),
- F_BASIC(184320000, SRC_PLL3, 4, NOMINAL),
- F_BASIC(245760000, SRC_PLL3, 3, NOMINAL),
- F_BASIC(368640000, SRC_PLL3, 2, NOMINAL),
- F_BASIC(384000000, SRC_PLL1, 2, NOMINAL),
- F_BASIC(445500000, SRC_PLL4, 2, NOMINAL),
+static struct clk_freq_tbl clk_tbl_mdh[] = {
+ F_BASIC( 49150000, PLL3, 15, NOMINAL),
+ F_BASIC( 92160000, PLL3, 8, NOMINAL),
+ F_BASIC(122880000, PLL3, 6, NOMINAL),
+ F_BASIC(184320000, PLL3, 4, NOMINAL),
+ F_BASIC(245760000, PLL3, 3, NOMINAL),
+ F_BASIC(368640000, PLL3, 2, NOMINAL),
+ F_BASIC(384000000, PLL1, 2, NOMINAL),
+ F_BASIC(445500000, PLL4, 2, NOMINAL),
F_END,
};

-static const struct clk_freq_tbl clk_tbl_grp[] = {
- F_BASIC( 24576000, SRC_LPXO, 1, NOMINAL),
- F_BASIC( 46080000, SRC_PLL3, 16, NOMINAL),
- F_BASIC( 49152000, SRC_PLL3, 15, NOMINAL),
- F_BASIC( 52662875, SRC_PLL3, 14, NOMINAL),
- F_BASIC( 56713846, SRC_PLL3, 13, NOMINAL),
- F_BASIC( 61440000, SRC_PLL3, 12, NOMINAL),
- F_BASIC( 67025454, SRC_PLL3, 11, NOMINAL),
- F_BASIC( 73728000, SRC_PLL3, 10, NOMINAL),
- F_BASIC( 81920000, SRC_PLL3, 9, NOMINAL),
- F_BASIC( 92160000, SRC_PLL3, 8, NOMINAL),
- F_BASIC(105325714, SRC_PLL3, 7, NOMINAL),
- F_BASIC(122880000, SRC_PLL3, 6, NOMINAL),
- F_BASIC(147456000, SRC_PLL3, 5, NOMINAL),
- F_BASIC(184320000, SRC_PLL3, 4, NOMINAL),
- F_BASIC(192000000, SRC_PLL1, 4, NOMINAL),
- F_BASIC(245760000, SRC_PLL3, 3, HIGH),
+static struct clk_freq_tbl clk_tbl_grp[] = {
+ F_BASIC( 24576000, LPXO, 1, NOMINAL),
+ F_BASIC( 46080000, PLL3, 16, NOMINAL),
+ F_BASIC( 49152000, PLL3, 15, NOMINAL),
+ F_BASIC( 52662875, PLL3, 14, NOMINAL),
+ F_BASIC( 56713846, PLL3, 13, NOMINAL),
+ F_BASIC( 61440000, PLL3, 12, NOMINAL),
+ F_BASIC( 67025454, PLL3, 11, NOMINAL),
+ F_BASIC( 73728000, PLL3, 10, NOMINAL),
+ F_BASIC( 81920000, PLL3, 9, NOMINAL),
+ F_BASIC( 92160000, PLL3, 8, NOMINAL),
+ F_BASIC(105325714, PLL3, 7, NOMINAL),
+ F_BASIC(122880000, PLL3, 6, NOMINAL),
+ F_BASIC(147456000, PLL3, 5, NOMINAL),
+ F_BASIC(184320000, PLL3, 4, NOMINAL),
+ F_BASIC(192000000, PLL1, 4, NOMINAL),
+ F_BASIC(245760000, PLL3, 3, HIGH),
/* Sync to AXI. Hence this "rate" is not fixed. */
- F_RAW(1, SRC_AXI, 0, B(14), 0, NOMINAL),
+ F_RAW(1, SRC_AXI, 0, B(14), 0, 0, NOMINAL, NULL),
F_END,
};

-static const struct clk_freq_tbl clk_tbl_sdc1_3[] = {
- F_MND8( 144000, 19, 12, SRC_LPXO, 1, 1, 171, NOMINAL),
- F_MND8( 400000, 19, 12, SRC_LPXO, 1, 2, 123, NOMINAL),
- F_MND8(16027000, 19, 12, SRC_PLL3, 3, 14, 215, NOMINAL),
- F_MND8(17000000, 19, 12, SRC_PLL3, 4, 19, 206, NOMINAL),
- F_MND8(20480000, 19, 12, SRC_PLL3, 4, 23, 212, NOMINAL),
- F_MND8(24576000, 19, 12, SRC_LPXO, 1, 0, 0, NOMINAL),
- F_MND8(49152000, 19, 12, SRC_PLL3, 3, 1, 5, NOMINAL),
+static struct clk_freq_tbl clk_tbl_sdc1_3[] = {
+ F_MND8( 144000, 19, 12, LPXO, 1, 1, 171, NOMINAL),
+ F_MND8( 400000, 19, 12, LPXO, 1, 2, 123, NOMINAL),
+ F_MND8(16027000, 19, 12, PLL3, 3, 14, 215, NOMINAL),
+ F_MND8(17000000, 19, 12, PLL3, 4, 19, 206, NOMINAL),
+ F_MND8(20480000, 19, 12, PLL3, 4, 23, 212, NOMINAL),
+ F_MND8(24576000, 19, 12, LPXO, 1, 0, 0, NOMINAL),
+ F_MND8(49152000, 19, 12, PLL3, 3, 1, 5, NOMINAL),
F_END,
};

-static const struct clk_freq_tbl clk_tbl_sdc2_4[] = {
- F_MND8( 144000, 20, 13, SRC_LPXO, 1, 1, 171, NOMINAL),
- F_MND8( 400000, 20, 13, SRC_LPXO, 1, 2, 123, NOMINAL),
- F_MND8(16027000, 20, 13, SRC_PLL3, 3, 14, 215, NOMINAL),
- F_MND8(17000000, 20, 13, SRC_PLL3, 4, 19, 206, NOMINAL),
- F_MND8(20480000, 20, 13, SRC_PLL3, 4, 23, 212, NOMINAL),
- F_MND8(24576000, 20, 13, SRC_LPXO, 1, 0, 0, NOMINAL),
- F_MND8(49152000, 20, 13, SRC_PLL3, 3, 1, 5, NOMINAL),
+static struct clk_freq_tbl clk_tbl_sdc2_4[] = {
+ F_MND8( 144000, 20, 13, LPXO, 1, 1, 171, NOMINAL),
+ F_MND8( 400000, 20, 13, LPXO, 1, 2, 123, NOMINAL),
+ F_MND8(16027000, 20, 13, PLL3, 3, 14, 215, NOMINAL),
+ F_MND8(17000000, 20, 13, PLL3, 4, 19, 206, NOMINAL),
+ F_MND8(20480000, 20, 13, PLL3, 4, 23, 212, NOMINAL),
+ F_MND8(24576000, 20, 13, LPXO, 1, 0, 0, NOMINAL),
+ F_MND8(49152000, 20, 13, PLL3, 3, 1, 5, NOMINAL),
F_END,
};

-static const struct clk_freq_tbl clk_tbl_mdp_core[] = {
- F_BASIC( 46080000, SRC_PLL3, 16, NOMINAL),
- F_BASIC( 49152000, SRC_PLL3, 15, NOMINAL),
- F_BASIC( 52663000, SRC_PLL3, 14, NOMINAL),
- F_BASIC( 92160000, SRC_PLL3, 8, NOMINAL),
- F_BASIC(122880000, SRC_PLL3, 6, NOMINAL),
- F_BASIC(147456000, SRC_PLL3, 5, NOMINAL),
- F_BASIC(153600000, SRC_PLL1, 5, NOMINAL),
- F_BASIC(192000000, SRC_PLL1, 4, HIGH),
+static struct clk_freq_tbl clk_tbl_mdp_core[] = {
+ F_BASIC( 46080000, PLL3, 16, NOMINAL),
+ F_BASIC( 49152000, PLL3, 15, NOMINAL),
+ F_BASIC( 52663000, PLL3, 14, NOMINAL),
+ F_BASIC( 92160000, PLL3, 8, NOMINAL),
+ F_BASIC(122880000, PLL3, 6, NOMINAL),
+ F_BASIC(147456000, PLL3, 5, NOMINAL),
+ F_BASIC(153600000, PLL1, 5, NOMINAL),
+ F_BASIC(192000000, PLL1, 4, HIGH),
F_END,
};

-static const struct clk_freq_tbl clk_tbl_mdp_lcdc[] = {
- F_MND16(24576000, SRC_LPXO, 1, 0, 0, NOMINAL),
- F_MND16(30720000, SRC_PLL3, 4, 1, 6, NOMINAL),
- F_MND16(32768000, SRC_PLL3, 3, 2, 15, NOMINAL),
- F_MND16(40960000, SRC_PLL3, 2, 1, 9, NOMINAL),
- F_MND16(73728000, SRC_PLL3, 2, 1, 5, NOMINAL),
+static struct clk_freq_tbl clk_tbl_mdp_lcdc[] = {
+ F_MND16(24576000, LPXO, 1, 0, 0, NOMINAL),
+ F_MND16(30720000, PLL3, 4, 1, 6, NOMINAL),
+ F_MND16(32768000, PLL3, 3, 2, 15, NOMINAL),
+ F_MND16(40960000, PLL3, 2, 1, 9, NOMINAL),
+ F_MND16(73728000, PLL3, 2, 1, 5, NOMINAL),
F_END,
};

-static const struct clk_freq_tbl clk_tbl_mdp_vsync[] = {
- F_RAW(24576000, SRC_LPXO, 0, 0, 0, NOMINAL),
+static struct clk_freq_tbl clk_tbl_mdp_vsync[] = {
+ F_RAW(24576000, SRC_LPXO, 0, 0, 0, 0, NOMINAL, NULL),
F_END,
};

-static const struct clk_freq_tbl clk_tbl_mi2s_codec[] = {
- F_MND16( 2048000, SRC_LPXO, 4, 1, 3, NOMINAL),
- F_MND16(12288000, SRC_LPXO, 2, 0, 0, NOMINAL),
+static struct clk_freq_tbl clk_tbl_mi2s_codec[] = {
+ F_MND16( 2048000, LPXO, 4, 1, 3, NOMINAL),
+ F_MND16(12288000, LPXO, 2, 0, 0, NOMINAL),
F_END,
};

-static const struct clk_freq_tbl clk_tbl_mi2s[] = {
- F_MND16(12288000, SRC_LPXO, 2, 0, 0, NOMINAL),
+static struct clk_freq_tbl clk_tbl_mi2s[] = {
+ F_MND16(12288000, LPXO, 2, 0, 0, NOMINAL),
F_END,
};

-static const struct clk_freq_tbl clk_tbl_midi[] = {
- F_MND8(98304000, 19, 12, SRC_PLL3, 3, 2, 5, NOMINAL),
+static struct clk_freq_tbl clk_tbl_midi[] = {
+ F_MND8(98304000, 19, 12, PLL3, 3, 2, 5, NOMINAL),
F_END,
};

-static const struct clk_freq_tbl clk_tbl_sdac[] = {
- F_MND16( 256000, SRC_LPXO, 4, 1, 24, NOMINAL),
- F_MND16( 352800, SRC_LPXO, 1, 147, 10240, NOMINAL),
- F_MND16( 384000, SRC_LPXO, 4, 1, 16, NOMINAL),
- F_MND16( 512000, SRC_LPXO, 4, 1, 12, NOMINAL),
- F_MND16( 705600, SRC_LPXO, 1, 147, 5120, NOMINAL),
- F_MND16( 768000, SRC_LPXO, 4, 1, 8, NOMINAL),
- F_MND16(1024000, SRC_LPXO, 4, 1, 6, NOMINAL),
- F_MND16(1411200, SRC_LPXO, 1, 147, 2560, NOMINAL),
- F_MND16(1536000, SRC_LPXO, 4, 1, 4, NOMINAL),
+static struct clk_freq_tbl clk_tbl_sdac[] = {
+ F_MND16( 256000, LPXO, 4, 1, 24, NOMINAL),
+ F_MND16( 352800, LPXO, 1, 147, 10240, NOMINAL),
+ F_MND16( 384000, LPXO, 4, 1, 16, NOMINAL),
+ F_MND16( 512000, LPXO, 4, 1, 12, NOMINAL),
+ F_MND16( 705600, LPXO, 1, 147, 5120, NOMINAL),
+ F_MND16( 768000, LPXO, 4, 1, 8, NOMINAL),
+ F_MND16(1024000, LPXO, 4, 1, 6, NOMINAL),
+ F_MND16(1411200, LPXO, 1, 147, 2560, NOMINAL),
+ F_MND16(1536000, LPXO, 4, 1, 4, NOMINAL),
F_END,
};

-static const struct clk_freq_tbl clk_tbl_tv[] = {
- F_MND8(27000000, 23, 16, SRC_PLL4, 2, 2, 33, NOMINAL),
- F_MND8(74250000, 23, 16, SRC_PLL4, 2, 1, 6, NOMINAL),
+static struct clk_freq_tbl clk_tbl_tv[] = {
+ F_MND8(27000000, 23, 16, PLL4, 2, 2, 33, NOMINAL),
+ F_MND8(74250000, 23, 16, PLL4, 2, 1, 6, NOMINAL),
F_END,
};

-static const struct clk_freq_tbl clk_tbl_usb[] = {
- F_MND8(60000000, 23, 16, SRC_PLL1, 2, 5, 32, NOMINAL),
+static struct clk_freq_tbl clk_tbl_usb[] = {
+ F_MND8(60000000, 23, 16, PLL1, 2, 5, 32, NOMINAL),
F_END,
};

-static const struct clk_freq_tbl clk_tbl_vfe_jpeg[] = {
- F_MND16( 36864000, SRC_PLL3, 4, 1, 5, NOMINAL),
- F_MND16( 46080000, SRC_PLL3, 4, 1, 4, NOMINAL),
- F_MND16( 61440000, SRC_PLL3, 4, 1, 3, NOMINAL),
- F_MND16( 73728000, SRC_PLL3, 2, 1, 5, NOMINAL),
- F_MND16( 81920000, SRC_PLL3, 3, 1, 3, NOMINAL),
- F_MND16( 92160000, SRC_PLL3, 4, 1, 2, NOMINAL),
- F_MND16( 98304000, SRC_PLL3, 3, 2, 5, NOMINAL),
- F_MND16(105326000, SRC_PLL3, 2, 2, 7, NOMINAL),
- F_MND16(122880000, SRC_PLL3, 2, 1, 3, NOMINAL),
- F_MND16(147456000, SRC_PLL3, 2, 2, 5, NOMINAL),
- F_MND16(153600000, SRC_PLL1, 2, 2, 5, NOMINAL),
+static struct clk_freq_tbl clk_tbl_vfe_jpeg[] = {
+ F_MND16( 36864000, PLL3, 4, 1, 5, NOMINAL),
+ F_MND16( 46080000, PLL3, 4, 1, 4, NOMINAL),
+ F_MND16( 61440000, PLL3, 4, 1, 3, NOMINAL),
+ F_MND16( 73728000, PLL3, 2, 1, 5, NOMINAL),
+ F_MND16( 81920000, PLL3, 3, 1, 3, NOMINAL),
+ F_MND16( 92160000, PLL3, 4, 1, 2, NOMINAL),
+ F_MND16( 98304000, PLL3, 3, 2, 5, NOMINAL),
+ F_MND16(105326000, PLL3, 2, 2, 7, NOMINAL),
+ F_MND16(122880000, PLL3, 2, 1, 3, NOMINAL),
+ F_MND16(147456000, PLL3, 2, 2, 5, NOMINAL),
+ F_MND16(153600000, PLL1, 2, 2, 5, NOMINAL),
F_END,
};

-static const struct clk_freq_tbl clk_tbl_cam[] = {
- F_MND16( 6000000, SRC_PLL1, 4, 1, 32, NOMINAL),
- F_MND16( 8000000, SRC_PLL1, 4, 1, 24, NOMINAL),
- F_MND16(12000000, SRC_PLL1, 4, 1, 16, NOMINAL),
- F_MND16(16000000, SRC_PLL1, 4, 1, 12, NOMINAL),
- F_MND16(19200000, SRC_PLL1, 4, 1, 10, NOMINAL),
- F_MND16(24000000, SRC_PLL1, 4, 1, 8, NOMINAL),
- F_MND16(32000000, SRC_PLL1, 4, 1, 6, NOMINAL),
- F_MND16(48000000, SRC_PLL1, 4, 1, 4, NOMINAL),
- F_MND16(64000000, SRC_PLL1, 4, 1, 3, NOMINAL),
+static struct clk_freq_tbl clk_tbl_cam[] = {
+ F_MND16( 6000000, PLL1, 4, 1, 32, NOMINAL),
+ F_MND16( 8000000, PLL1, 4, 1, 24, NOMINAL),
+ F_MND16(12000000, PLL1, 4, 1, 16, NOMINAL),
+ F_MND16(16000000, PLL1, 4, 1, 12, NOMINAL),
+ F_MND16(19200000, PLL1, 4, 1, 10, NOMINAL),
+ F_MND16(24000000, PLL1, 4, 1, 8, NOMINAL),
+ F_MND16(32000000, PLL1, 4, 1, 6, NOMINAL),
+ F_MND16(48000000, PLL1, 4, 1, 4, NOMINAL),
+ F_MND16(64000000, PLL1, 4, 1, 3, NOMINAL),
F_END,
};

-static const struct clk_freq_tbl clk_tbl_vpe[] = {
- F_MND8( 24576000, 22, 15, SRC_LPXO, 1, 0, 0, NOMINAL),
- F_MND8( 30720000, 22, 15, SRC_PLL3, 4, 1, 6, NOMINAL),
- F_MND8( 61440000, 22, 15, SRC_PLL3, 4, 1, 3, NOMINAL),
- F_MND8( 81920000, 22, 15, SRC_PLL3, 3, 1, 3, NOMINAL),
- F_MND8(122880000, 22, 15, SRC_PLL3, 3, 1, 2, NOMINAL),
- F_MND8(147456000, 22, 15, SRC_PLL3, 1, 1, 5, NOMINAL),
- F_MND8(153600000, 22, 15, SRC_PLL1, 1, 1, 5, NOMINAL),
+static struct clk_freq_tbl clk_tbl_vpe[] = {
+ F_MND8( 24576000, 22, 15, LPXO, 1, 0, 0, NOMINAL),
+ F_MND8( 30720000, 22, 15, PLL3, 4, 1, 6, NOMINAL),
+ F_MND8( 61440000, 22, 15, PLL3, 4, 1, 3, NOMINAL),
+ F_MND8( 81920000, 22, 15, PLL3, 3, 1, 3, NOMINAL),
+ F_MND8(122880000, 22, 15, PLL3, 3, 1, 2, NOMINAL),
+ F_MND8(147456000, 22, 15, PLL3, 1, 1, 5, NOMINAL),
+ F_MND8(153600000, 22, 15, PLL1, 1, 1, 5, NOMINAL),
F_END,
};

-static const struct clk_freq_tbl clk_tbl_mfc[] = {
- F_MND8( 24576000, 24, 17, SRC_LPXO, 1, 0, 0, NOMINAL),
- F_MND8( 30720000, 24, 17, SRC_PLL3, 4, 1, 6, NOMINAL),
- F_MND8( 61440000, 24, 17, SRC_PLL3, 4, 1, 3, NOMINAL),
- F_MND8( 81920000, 24, 17, SRC_PLL3, 3, 1, 3, NOMINAL),
- F_MND8(122880000, 24, 17, SRC_PLL3, 3, 1, 2, NOMINAL),
- F_MND8(147456000, 24, 17, SRC_PLL3, 1, 1, 5, NOMINAL),
- F_MND8(153600000, 24, 17, SRC_PLL1, 1, 1, 5, NOMINAL),
- F_MND8(170667000, 24, 17, SRC_PLL1, 1, 2, 9, NOMINAL),
+static struct clk_freq_tbl clk_tbl_mfc[] = {
+ F_MND8( 24576000, 24, 17, LPXO, 1, 0, 0, NOMINAL),
+ F_MND8( 30720000, 24, 17, PLL3, 4, 1, 6, NOMINAL),
+ F_MND8( 61440000, 24, 17, PLL3, 4, 1, 3, NOMINAL),
+ F_MND8( 81920000, 24, 17, PLL3, 3, 1, 3, NOMINAL),
+ F_MND8(122880000, 24, 17, PLL3, 3, 1, 2, NOMINAL),
+ F_MND8(147456000, 24, 17, PLL3, 1, 1, 5, NOMINAL),
+ F_MND8(153600000, 24, 17, PLL1, 1, 1, 5, NOMINAL),
+ F_MND8(170667000, 24, 17, PLL1, 1, 2, 9, NOMINAL),
F_END,
};

-static const struct clk_freq_tbl clk_tbl_spi[] = {
- F_MND8( 9963243, 19, 12, SRC_PLL3, 4, 7, 129, NOMINAL),
- F_MND8(26331429, 19, 12, SRC_PLL3, 4, 34, 241, NOMINAL),
+static struct clk_freq_tbl clk_tbl_spi[] = {
+ F_MND8( 9963243, 19, 12, PLL3, 4, 7, 129, NOMINAL),
+ F_MND8(26331429, 19, 12, PLL3, 4, 34, 241, NOMINAL),
F_END,
};

-static const struct clk_freq_tbl clk_tbl_lpa_codec[] = {
- F_RAW(1, SRC_NONE, 0, 0, 0, MSMC1_END), /* src = MI2S_CODEC_RX */
- F_RAW(2, SRC_NONE, 0, 1, 0, MSMC1_END), /* src = ECODEC_CIF */
- F_RAW(3, SRC_NONE, 0, 2, 0, MSMC1_END), /* src = MI2S */
- F_RAW(4, SRC_NONE, 0, 3, 0, MSMC1_END), /* src = SDAC */
+static struct clk_freq_tbl clk_tbl_lpa_codec[] = {
+ F_RAW(1, SRC_NONE, 0, 0, 0, 0, LOW, NULL), /* src = MI2S_CODEC_RX */
+ F_RAW(2, SRC_NONE, 0, 1, 0, 0, LOW, NULL), /* src = ECODEC_CIF */
+ F_RAW(3, SRC_NONE, 0, 2, 0, 0, LOW, NULL), /* src = MI2S */
+ F_RAW(4, SRC_NONE, 0, 3, 0, 0, LOW, NULL), /* src = SDAC */
F_END,
};

-static struct clk_freq_tbl dummy_freq = F_END;
-
-#define MND 1 /* Integer predivider and fractional MN:D divider. */
-#define BASIC 2 /* Integer divider. */
-#define NORATE 3 /* Just on/off. */
-
-#define C(x) L_7X30_##x##_CLK
-
-#define CLK_LOCAL(id, t, md, ns, f_msk, br, root, tbl, \
- par, chld_lst, h, hm, tv) \
- [C(id)] = { \
- .type = t, \
- .md_reg = md, \
- .ns_reg = ns, \
- .freq_mask = f_msk, \
- .br_en_mask = br, \
- .root_en_mask = root, \
- .parent = C(par), \
- .children = chld_lst, \
- .freq_tbl = tbl, \
- .current_freq = &dummy_freq, \
- .halt_reg = h, \
- .halt_mask = hm, \
- .test_vector = tv, \
- }
-
-#define CLK_BASIC(id, ns, br, root, tbl, par, h, hm, tv) \
- CLK_LOCAL(id, BASIC, 0, ns, F_MASK_BASIC, br, root, tbl, \
- par, NULL, h, hm, tv)
-#define CLK_MND8_P(id, ns, m, l, br, root, tbl, par, chld_lst, h, hm, tv) \
- CLK_LOCAL(id, MND, (ns-4), ns, F_MASK_MND8(m, l), br, root, \
- tbl, par, chld_lst, h, hm, tv)
-#define CLK_MND8(id, ns, m, l, br, root, tbl, chld_lst, h, hm, tv) \
- CLK_MND8_P(id, ns, m, l, br, root, tbl, NONE, chld_lst, \
- h, hm, tv)
-#define CLK_MND16(id, ns, br, root, tbl, par, chld_lst, h, hm, tv) \
- CLK_LOCAL(id, MND, (ns-4), ns, F_MASK_MND16, br, root, tbl, \
- par, chld_lst, h, hm, tv)
-#define CLK_1RATE(id, ns, br, root, tbl, h, hm, tv) \
- CLK_LOCAL(id, BASIC, 0, ns, 0, br, root, tbl, NONE, NULL, \
- h, hm, tv)
-#define CLK_SLAVE(id, ns, br, par, h, hm, tv) \
- CLK_LOCAL(id, NORATE, 0, ns, 0, br, 0, NULL, par, NULL, \
- h, hm, tv)
-#define CLK_NORATE(id, ns, br, root, h, hm, tv) \
- CLK_LOCAL(id, NORATE, 0, ns, 0, br, root, NULL, NONE, NULL, \
- h, hm, tv)
-#define CLK_GLBL(id, glbl, br, h, hm, tv) \
- CLK_LOCAL(id, NORATE, 0, glbl, 0, br, 0, NULL, GLBL_ROOT, \
- NULL, h, hm, tv)
-#define CLK_BRIDGE(id, glbl, br, par, h, hm, tv) \
- CLK_LOCAL(id, NORATE, 0, glbl, 0, br, 0, NULL, par, NULL, \
- h, hm, tv)
-
-static uint32_t *pll_status_addr[NUM_PLL] = {
- [PLL_0] = PLL0_STATUS_BASE_REG,
- [PLL_1] = PLL1_STATUS_BASE_REG,
- [PLL_2] = PLL2_STATUS_BASE_REG,
- [PLL_3] = PLL3_STATUS_BASE_REG,
- [PLL_4] = PLL4_STATUS_BASE_REG,
- [PLL_5] = PLL5_STATUS_BASE_REG,
- [PLL_6] = PLL6_STATUS_BASE_REG,
-};
-
-static uint32_t pll_count[NUM_PLL];
-
-static uint32_t chld_grp_3d_src[] = {C(IMEM), C(GRP_3D), C(NONE)};
-static uint32_t chld_mdp_lcdc_p[] = {C(MDP_LCDC_PAD_PCLK), C(NONE)};
-static uint32_t chld_mfc[] = {C(MFC_DIV2), C(NONE)};
-static uint32_t chld_mi2s_codec_rx[] = {C(MI2S_CODEC_RX_S), C(NONE)};
-static uint32_t chld_mi2s_codec_tx[] = {C(MI2S_CODEC_TX_S), C(NONE)};
-static uint32_t chld_mi2s[] = {C(MI2S_S), C(NONE)};
-static uint32_t chld_sdac[] = {C(SDAC_M), C(NONE)};
-static uint32_t chld_tv[] = {C(TV_DAC), C(TV_ENC), C(TSIF_REF),
- C(HDMI), C(NONE)};
-static uint32_t chld_usb_src[] = {C(USB_HS), C(USB_HS_CORE),
+/*
+ * Clock children lists
+ */
+static const uint32_t chld_grp_3d_src[] = {C(IMEM), C(GRP_3D), C(NONE)};
+static const uint32_t chld_mdp_lcdc_p[] = {C(MDP_LCDC_PAD_PCLK), C(NONE)};
+static const uint32_t chld_mfc[] = {C(MFC_DIV2), C(NONE)};
+static const uint32_t chld_mi2s_codec_rx[] = {C(MI2S_CODEC_RX_S), C(NONE)};
+static const uint32_t chld_mi2s_codec_tx[] = {C(MI2S_CODEC_TX_S), C(NONE)};
+static const uint32_t chld_mi2s[] = {C(MI2S_S), C(NONE)};
+static const uint32_t chld_sdac[] = {C(SDAC_M), C(NONE)};
+static const uint32_t chld_tv[] = {C(TV_DAC), C(TV_ENC), C(HDMI),
+ C(TSIF_REF), C(NONE)};
+static const uint32_t chld_usb_src[] = {C(USB_HS), C(USB_HS_CORE),
C(USB_HS2), C(USB_HS2_CORE),
C(USB_HS3), C(USB_HS3_CORE),
C(NONE)};
-static uint32_t chld_vfe[] = {C(VFE_MDC), C(VFE_CAMIF), C(CSI0_VFE),
+static uint32_t const chld_vfe[] = {C(VFE_MDC), C(VFE_CAMIF), C(CSI0_VFE),
C(NONE)};

-static struct clk_local clk_local_tbl[] = {
+/*
+ * Clock declaration macros
+ */
+#define CLK_BASIC(id, ns, br, root, tbl, par, h_r, h_c, h_b, tv) \
+ CLK(id, BASIC, ns, ns, NULL, NULL, 0, h_r, h_c, \
+ h_b, br, root, F_MASK_BASIC, 0, set_rate_basic, tbl, \
+ NULL, par, NULL, tv)
+#define CLK_MND8_P(id, ns, m, l, br, root, tbl, par, chld_lst, \
+ h_r, h_c, h_b, tv) \
+ CLK(id, MND, ns, ns, (ns-4), NULL, 0, h_r, h_c, \
+ h_b, br, root, F_MASK_MND8(m, l), 0, set_rate_mnd, \
+ tbl, NULL, par, chld_lst, tv)
+#define CLK_MND8(id, ns, m, l, br, root, tbl, chld_lst, h_r, h_c, h_b, tv) \
+ CLK_MND8_P(id, ns, m, l, br, root, tbl, NONE, chld_lst, \
+ h_r, h_c, h_b, tv)
+#define CLK_MND16(id, ns, br, root, tbl, par, chld_lst, h_r, h_c, h_b, tv) \
+ CLK(id, MND, ns, ns, (ns-4), NULL, 0, h_r, h_c, \
+ h_b, br, root, F_MASK_MND16, 0, set_rate_mnd, tbl, \
+ NULL, par, chld_lst, tv)
+#define CLK_1RATE(id, ns, br, root, tbl, h_r, h_c, h_b, tv) \
+ CLK(id, BASIC, NULL, ns, NULL, NULL, 0, h_r, h_c, \
+ h_b, br, root, 0, 0, set_rate_nop, tbl, \
+ NULL, NONE, NULL, tv)
+#define CLK_SLAVE(id, ns, br, par, h_r, h_c, h_b, tv) \
+ CLK(id, NORATE, NULL, ns, NULL, NULL, 0, h_r, h_c, \
+ h_b, br, 0, 0, 0, NULL, NULL, NULL, par, NULL, tv)
+#define CLK_NORATE(id, ns, br, root, h_r, h_c, h_b, tv) \
+ CLK(id, NORATE, NULL, ns, NULL, NULL, 0, h_r, h_c, \
+ h_b, br, root, 0, 0, NULL, NULL, NULL, NONE, NULL, tv)
+#define CLK_GLBL(id, glbl, br, h_r, h_c, h_b, tv) \
+ CLK(id, NORATE, NULL, glbl, NULL, NULL, 0, h_r, h_c, \
+ h_b, br, 0, 0, 0, NULL, NULL, NULL, NONE, NULL, tv)
+#define CLK_BRIDGE(id, glbl, br, par, h_r, h_c, h_b, tv) \
+ CLK(id, NORATE, NULL, glbl, NULL, NULL, 0, h_r, h_c, \
+ h_b, br, 0, 0, 0, NULL, NULL, NULL, par, NULL, tv)
+
+/*
+ * Clock table
+ */
+struct clk_local soc_clk_local_tbl[] = {
CLK_NORATE(MDC, MDC_NS_REG, B(9), B(11),
- CLK_HALT_STATEA_REG, 10, 0x4D56),
+ CLK_HALT_STATEA_REG, HALT, 10, 0x4D56),
CLK_NORATE(LPA_CORE, LPA_NS_REG, B(5), 0,
- CLK_HALT_STATEC_REG, 5, 0x0E),
+ CLK_HALT_STATEC_REG, HALT, 5, 0x0E),

CLK_1RATE(I2C, I2C_NS_REG, B(9), B(11), clk_tbl_tcxo,
- CLK_HALT_STATEA_REG, 15, 0x4D4D),
+ CLK_HALT_STATEA_REG, HALT, 15, 0x4D4D),
CLK_1RATE(I2C_2, I2C_2_NS_REG, B(0), B(2), clk_tbl_tcxo,
- CLK_HALT_STATEC_REG, 2, 0x0B),
+ CLK_HALT_STATEC_REG, HALT, 2, 0x0B),
CLK_1RATE(QUP_I2C, QUP_I2C_NS_REG, B(0), B(2), clk_tbl_tcxo,
- CLK_HALT_STATEB_REG, 31, 0x1C),
+ CLK_HALT_STATEB_REG, HALT, 31, 0x1C),
CLK_1RATE(UART1, UART_NS_REG, B(5), B(4), clk_tbl_tcxo,
- CLK_HALT_STATEB_REG, 7, 0x4D6F),
+ CLK_HALT_STATEB_REG, HALT, 7, 0x4D6F),
CLK_1RATE(UART2, UART2_NS_REG, B(5), B(4), clk_tbl_tcxo,
- CLK_HALT_STATEB_REG, 5, 0x4D71),
+ CLK_HALT_STATEB_REG, HALT, 5, 0x4D71),

CLK_BASIC(EMDH, EMDH_NS_REG, 0, B(11), clk_tbl_mdh, AXI_LI_ADSP_A,
- NULL, 0, 0x4F00),
+ NULL, DELAY, 0, 0x4F00),
CLK_BASIC(PMDH, PMDH_NS_REG, 0, B(11), clk_tbl_mdh, AXI_LI_ADSP_A,
- NULL, 0, 0x5500),
+ NULL, DELAY, 0, 0x5500),
CLK_BASIC(MDP, MDP_NS_REG, B(9), B(11), clk_tbl_mdp_core, AXI_MDP,
- CLK_HALT_STATEB_REG, 16, 0x5400),
+ CLK_HALT_STATEB_REG, HALT, 16, 0x5400),

CLK_MND8_P(VPE, VPE_NS_REG, 22, 15, B(9), B(11), clk_tbl_vpe,
- AXI_VPE, NULL, CLK_HALT_STATEC_REG, 10, 0x6C00),
+ AXI_VPE, NULL, CLK_HALT_STATEC_REG, HALT, 10, 0x6C00),
CLK_MND8_P(MFC, MFC_NS_REG, 24, 17, B(9), B(11), clk_tbl_mfc,
AXI_MFC, chld_mfc, CLK_HALT_STATEC_REG,
- 12, 0x38),
+ HALT, 12, 0x38),
CLK_SLAVE(MFC_DIV2, MFC_NS_REG, B(15), MFC, CLK_HALT_STATEC_REG,
- 11, 0x1F),
+ HALT, 11, 0x1F),

CLK_MND8(SDC1, SDCn_NS_REG(1), 19, 12, B(9), B(11), clk_tbl_sdc1_3,
- NULL, CLK_HALT_STATEA_REG, 1, 0x4D62),
+ NULL, CLK_HALT_STATEA_REG, HALT, 1, 0x4D62),
CLK_MND8(SDC2, SDCn_NS_REG(2), 20, 13, B(9), B(11), clk_tbl_sdc2_4,
- NULL, CLK_HALT_STATEA_REG, 0, 0x4D64),
+ NULL, CLK_HALT_STATEA_REG, HALT, 0, 0x4D64),
CLK_MND8(SDC3, SDCn_NS_REG(3), 19, 12, B(9), B(11), clk_tbl_sdc1_3,
- NULL, CLK_HALT_STATEB_REG, 24, 0x4D7A),
+ NULL, CLK_HALT_STATEB_REG, HALT, 24, 0x4D7A),
CLK_MND8(SDC4, SDCn_NS_REG(4), 20, 13, B(9), B(11), clk_tbl_sdc2_4,
- NULL, CLK_HALT_STATEB_REG, 25, 0x4D7C),
+ NULL, CLK_HALT_STATEB_REG, HALT, 25, 0x4D7C),
CLK_MND8(SPI, SPI_NS_REG, 19, 12, B(9), B(11), clk_tbl_spi, NULL,
- CLK_HALT_STATEC_REG, 0, 0x09),
+ CLK_HALT_STATEC_REG, HALT, 0, 0x09),
CLK_MND8(MIDI, MIDI_NS_REG, 19, 12, B(9), B(11), clk_tbl_midi, NULL,
- CLK_HALT_STATEC_REG, 1, 0x0A),
+ CLK_HALT_STATEC_REG, HALT, 1, 0x0A),
CLK_MND8_P(USB_HS_SRC, USBH_NS_REG, 23, 16, 0, B(11), clk_tbl_usb,
- AXI_LI_ADSP_A, chld_usb_src, NULL, 0, 0),
+ AXI_LI_ADSP_A, chld_usb_src, NULL, NOCHECK, 0, 0),
CLK_SLAVE(USB_HS, USBH_NS_REG, B(9), USB_HS_SRC,
- CLK_HALT_STATEB_REG, 26, 0x4D7F),
+ CLK_HALT_STATEB_REG, HALT, 26, 0x4D7F),
CLK_SLAVE(USB_HS_CORE, USBH_NS_REG, B(13), USB_HS_SRC,
- CLK_HALT_STATEA_REG, 27, 0x14),
+ CLK_HALT_STATEA_REG, HALT, 27, 0x14),
CLK_SLAVE(USB_HS2, USBH2_NS_REG, B(9), USB_HS_SRC,
- CLK_HALT_STATEB_REG, 3, 0x4D73),
+ CLK_HALT_STATEB_REG, HALT, 3, 0x4D73),
CLK_SLAVE(USB_HS2_CORE, USBH2_NS_REG, B(4), USB_HS_SRC,
- CLK_HALT_STATEA_REG, 28, 0x15),
+ CLK_HALT_STATEA_REG, HALT, 28, 0x15),
CLK_SLAVE(USB_HS3, USBH3_NS_REG, B(9), USB_HS_SRC,
- CLK_HALT_STATEB_REG, 2, 0x4D74),
+ CLK_HALT_STATEB_REG, HALT, 2, 0x4D74),
CLK_SLAVE(USB_HS3_CORE, USBH3_NS_REG, B(4), USB_HS_SRC,
- CLK_HALT_STATEA_REG, 29, 0x16),
+ CLK_HALT_STATEA_REG, HALT, 29, 0x16),
CLK_MND8(TV, TV_NS_REG, 23, 16, 0, B(11), clk_tbl_tv, chld_tv,
- NULL, 0, 0),
+ NULL, NOCHECK, 0, 0),
CLK_SLAVE(HDMI, HDMI_NS_REG, B(9), TV,
- CLK_HALT_STATEC_REG, 7, 0x13),
+ CLK_HALT_STATEC_REG, HALT, 7, 0x13),
CLK_SLAVE(TV_DAC, TV_NS_REG, B(12), TV,
- CLK_HALT_STATEB_REG, 27, 0x4D6C),
+ CLK_HALT_STATEB_REG, HALT, 27, 0x4D6C),
CLK_SLAVE(TV_ENC, TV_NS_REG, B(9), TV,
- CLK_HALT_STATEB_REG, 10, 0x4D6B),
+ CLK_HALT_STATEB_REG, HALT, 10, 0x4D6B),
/* Hacking root & branch into one param. */
CLK_SLAVE(TSIF_REF, TSIF_NS_REG, B(9)|B(11), TV,
- CLK_HALT_STATEB_REG, 11, 0x4D6A),
+ CLK_HALT_STATEB_REG, HALT, 11, 0x4D6A),

CLK_MND16(UART1DM, UART1DM_NS_REG, B(9), B(11), clk_tbl_uartdm, NONE,
- NULL, CLK_HALT_STATEB_REG, 6, 0x4D70),
+ NULL, CLK_HALT_STATEB_REG, HALT, 6, 0x4D70),
CLK_MND16(UART2DM, UART2DM_NS_REG, B(9), B(11), clk_tbl_uartdm, NONE,
- NULL, CLK_HALT_STATEB_REG, 23, 0x4D7D),
+ NULL, CLK_HALT_STATEB_REG, HALT, 23, 0x4D7D),
CLK_MND16(JPEG, JPEG_NS_REG, B(9), B(11), clk_tbl_vfe_jpeg, AXI_LI_JPEG,
- NULL, CLK_HALT_STATEB_REG, 1, 0x6000),
+ NULL, CLK_HALT_STATEB_REG, HALT, 1, 0x6000),
CLK_MND16(CAM_M, CAM_NS_REG, 0, B(9), clk_tbl_cam, NONE, NULL,
- NULL, 0, 0x4D44),
+ NULL, DELAY, 0, 0x4D44),
CLK_MND16(VFE, CAM_VFE_NS_REG, B(9), B(13), clk_tbl_vfe_jpeg,
AXI_LI_VFE, chld_vfe, CLK_HALT_STATEB_REG,
- 0, 0x4D76),
+ HALT, 0, 0x4D76),
CLK_SLAVE(VFE_MDC, CAM_VFE_NS_REG, B(11), VFE, CLK_HALT_STATEA_REG,
- 9, 0x4D57),
+ HALT, 9, 0x4D57),
CLK_SLAVE(VFE_CAMIF, CAM_VFE_NS_REG, B(15), VFE, CLK_HALT_STATEC_REG,
- 13, 0x7000),
+ HALT, 13, 0x7000),
CLK_SLAVE(CSI0_VFE, CSI_NS_REG, B(15), VFE, CLK_HALT_STATEC_REG,
- 16, 0),
+ HALT, 16, 0),

CLK_MND16(SDAC, SDAC_NS_REG, B(9), B(11), clk_tbl_sdac,
- NONE, chld_sdac, CLK_HALT_STATEA_REG, 2, 0x4D60),
+ NONE, chld_sdac, CLK_HALT_STATEA_REG, HALT, 2, 0x4D60),
CLK_SLAVE(SDAC_M, SDAC_NS_REG, B(12), SDAC, CLK_HALT_STATEB_REG,
- 17, 0x4D66),
+ HALT, 17, 0x4D66),

CLK_MND16(MDP_LCDC_PCLK, MDP_LCDC_NS_REG, B(9), B(11),
clk_tbl_mdp_lcdc, NONE, chld_mdp_lcdc_p,
- CLK_HALT_STATEB_REG, 28, 0x4200),
+ CLK_HALT_STATEB_REG, HALT, 28, 0x4200),
CLK_SLAVE(MDP_LCDC_PAD_PCLK, MDP_LCDC_NS_REG, B(12), MDP_LCDC_PCLK,
- CLK_HALT_STATEB_REG, 29, 0x4100),
+ CLK_HALT_STATEB_REG, HALT, 29, 0x4100),
CLK_1RATE(MDP_VSYNC, MDP_VSYNC_REG, B(0), 0, clk_tbl_mdp_vsync,
- CLK_HALT_STATEB_REG, 30, 0x4D53),
+ CLK_HALT_STATEB_REG, HALT, 30, 0x4D53),

CLK_MND16(MI2S_CODEC_RX_M, MI2S_RX_NS_REG, B(12), B(11),
clk_tbl_mi2s_codec, NONE, chld_mi2s_codec_rx,
- CLK_HALT_STATEA_REG, 12, 0x4D4E),
+ CLK_HALT_STATEA_REG, HALT, 12, 0x4D4E),
CLK_SLAVE(MI2S_CODEC_RX_S, MI2S_RX_NS_REG, B(9), MI2S_CODEC_RX_M,
- CLK_HALT_STATEA_REG, 13, 0x4D4F),
+ CLK_HALT_STATEA_REG, HALT, 13, 0x4D4F),

CLK_MND16(MI2S_CODEC_TX_M, MI2S_TX_NS_REG, B(12), B(11),
clk_tbl_mi2s_codec, NONE, chld_mi2s_codec_tx,
- CLK_HALT_STATEC_REG, 8, 0x4D50),
+ CLK_HALT_STATEC_REG, HALT, 8, 0x4D50),
CLK_SLAVE(MI2S_CODEC_TX_S, MI2S_TX_NS_REG, B(9), MI2S_CODEC_TX_M,
- CLK_HALT_STATEA_REG, 11, 0x17),
+ CLK_HALT_STATEA_REG, HALT, 11, 0x17),

CLK_MND16(MI2S_M, MI2S_NS_REG, B(12), B(11),
clk_tbl_mi2s, NONE, chld_mi2s, CLK_HALT_STATEC_REG,
- 4, 0x0D),
+ HALT, 4, 0x0D),
CLK_SLAVE(MI2S_S, MI2S_NS_REG, B(9), MI2S_M, CLK_HALT_STATEC_REG,
- 3, 0),
-
- CLK_LOCAL(GRP_2D, BASIC, 0, GRP_2D_NS_REG, F_MASK_BASIC | (7 << 12),
- B(7), B(11), clk_tbl_grp, AXI_GRP_2D, NULL,
- CLK_HALT_STATEA_REG, 31, 0x5C00),
- CLK_LOCAL(GRP_3D_SRC, BASIC, 0, GRP_NS_REG, F_MASK_BASIC | (7 << 12),
- 0, B(11), clk_tbl_grp, AXI_LI_GRP, chld_grp_3d_src,
- 0, 0, 0),
+ HALT, 3, 0),
+
+ CLK(GRP_2D, BASIC, GRP_2D_NS_REG, GRP_2D_NS_REG, NULL, NULL, 0,
+ CLK_HALT_STATEA_REG, HALT, 31, B(7), B(11),
+ F_MASK_BASIC | (7 << 12), 0, set_rate_basic,
+ clk_tbl_grp, NULL, AXI_GRP_2D, NULL, 0x5C00),
+ CLK(GRP_3D_SRC, BASIC, GRP_NS_REG, GRP_NS_REG, NULL, NULL, 0,
+ NULL, NOCHECK, 0, 0, B(11), F_MASK_BASIC | (7 << 12),
+ 0, set_rate_basic, clk_tbl_grp, NULL, AXI_LI_GRP,
+ chld_grp_3d_src, 0),
CLK_SLAVE(GRP_3D, GRP_NS_REG, B(7), GRP_3D_SRC, CLK_HALT_STATEB_REG,
- 18, 0x5E00),
+ HALT, 18, 0x5E00),
CLK_SLAVE(IMEM, GRP_NS_REG, B(9), GRP_3D_SRC, CLK_HALT_STATEB_REG,
- 19, 0x5F00),
- CLK_LOCAL(LPA_CODEC, BASIC, 0, LPA_NS_REG, BM(1, 0), B(9), 0,
- clk_tbl_lpa_codec, NONE, NULL, CLK_HALT_STATEC_REG,
- 6, 0x0F),
+ HALT, 19, 0x5F00),
+ CLK(LPA_CODEC, BASIC, LPA_NS_REG, LPA_NS_REG, NULL, NULL, 0,
+ CLK_HALT_STATEC_REG, HALT, 6, B(9), 0, BM(1, 0), 0,
+ set_rate_basic, clk_tbl_lpa_codec, NULL, NONE, NULL,
+ 0x0F),

CLK_MND8(CSI0, CSI_NS_REG, 24, 17, B(9), B(11), clk_tbl_csi, NULL,
- CLK_HALT_STATEC_REG, 17, 0x5F00),
+ CLK_HALT_STATEC_REG, HALT, 17, 0x5F00),

/* For global clocks to be on we must have GLBL_ROOT_ENA set */
CLK_1RATE(GLBL_ROOT, GLBL_CLK_ENA_SC_REG, 0, B(29), clk_tbl_axi,
- NULL, 0, 0),
+ NULL, NOCHECK, 0, 0),

/* Peripheral bus clocks. */
CLK_BRIDGE(ADM, GLBL_CLK_ENA_SC_REG, B(5), AXI_LI_APPS,
- GLBL_CLK_STATE_REG, 5, 0x4000),
+ GLBL_CLK_STATE_REG, HALT_VOTED, 5, 0x4000),
CLK_GLBL(ADM_P, GLBL_CLK_ENA_2_SC_REG, B(15),
- GLBL_CLK_STATE_2_REG, 15, 0x11),
+ GLBL_CLK_STATE_2_REG, HALT_VOTED, 15, 0x11),
CLK_GLBL(CE, GLBL_CLK_ENA_SC_REG, B(6),
- GLBL_CLK_STATE_REG, 6, 0x4D43),
+ GLBL_CLK_STATE_REG, HALT_VOTED, 6, 0x4D43),
CLK_GLBL(CAMIF_PAD_P, GLBL_CLK_ENA_SC_REG, B(9),
- GLBL_CLK_STATE_REG, 9, 0x1A),
+ GLBL_CLK_STATE_REG, HALT_VOTED, 9, 0x1A),
CLK_GLBL(CSI0_P, GLBL_CLK_ENA_SC_REG, B(30),
- GLBL_CLK_STATE_REG, 30, 0),
+ GLBL_CLK_STATE_REG, HALT_VOTED, 30, 0),
CLK_GLBL(EMDH_P, GLBL_CLK_ENA_2_SC_REG, B(3),
- GLBL_CLK_STATE_2_REG, 3, 0x03),
+ GLBL_CLK_STATE_2_REG, HALT_VOTED, 3, 0x03),
CLK_GLBL(GRP_2D_P, GLBL_CLK_ENA_SC_REG, B(24),
- GLBL_CLK_STATE_REG, 24, 0x4D4C),
+ GLBL_CLK_STATE_REG, HALT_VOTED, 24, 0x4D4C),
CLK_GLBL(GRP_3D_P, GLBL_CLK_ENA_2_SC_REG, B(17),
- GLBL_CLK_STATE_2_REG, 17, 0x4D67),
+ GLBL_CLK_STATE_2_REG, HALT_VOTED, 17, 0x4D67),
CLK_GLBL(JPEG_P, GLBL_CLK_ENA_2_SC_REG, B(24),
- GLBL_CLK_STATE_2_REG, 24, 0x4D5E),
+ GLBL_CLK_STATE_2_REG, HALT_VOTED, 24, 0x4D5E),
CLK_GLBL(LPA_P, GLBL_CLK_ENA_2_SC_REG, B(7),
- GLBL_CLK_STATE_2_REG, 7, 0x07),
+ GLBL_CLK_STATE_2_REG, HALT_VOTED, 7, 0x07),
CLK_GLBL(MDP_P, GLBL_CLK_ENA_2_SC_REG, B(6),
- GLBL_CLK_STATE_2_REG, 6, 0x06),
+ GLBL_CLK_STATE_2_REG, HALT_VOTED, 6, 0x06),
CLK_GLBL(MFC_P, GLBL_CLK_ENA_2_SC_REG, B(26),
- GLBL_CLK_STATE_2_REG, 26, 0x4D75),
+ GLBL_CLK_STATE_2_REG, HALT_VOTED, 26, 0x4D75),
CLK_GLBL(PMDH_P, GLBL_CLK_ENA_2_SC_REG, B(4),
- GLBL_CLK_STATE_2_REG, 4, 0x04),
+ GLBL_CLK_STATE_2_REG, HALT_VOTED, 4, 0x04),
CLK_GLBL(ROTATOR_IMEM, GLBL_CLK_ENA_2_SC_REG, B(23),
- GLBL_CLK_STATE_2_REG, 23, 0x6600),
+ GLBL_CLK_STATE_2_REG, HALT_VOTED, 23, 0x6600),
CLK_GLBL(ROTATOR_P, GLBL_CLK_ENA_2_SC_REG, B(25),
- GLBL_CLK_STATE_2_REG, 25, 0x4D6D),
+ GLBL_CLK_STATE_2_REG, HALT_VOTED, 25, 0x4D6D),
CLK_GLBL(SDC1_P, GLBL_CLK_ENA_SC_REG, B(7),
- GLBL_CLK_STATE_REG, 7, 0x4D61),
+ GLBL_CLK_STATE_REG, HALT_VOTED, 7, 0x4D61),
CLK_GLBL(SDC2_P, GLBL_CLK_ENA_SC_REG, B(8),
- GLBL_CLK_STATE_REG, 8, 0x4F63),
+ GLBL_CLK_STATE_REG, HALT_VOTED, 8, 0x4F63),
CLK_GLBL(SDC3_P, GLBL_CLK_ENA_SC_REG, B(27),
- GLBL_CLK_STATE_REG, 27, 0x4D79),
+ GLBL_CLK_STATE_REG, HALT_VOTED, 27, 0x4D79),
CLK_GLBL(SDC4_P, GLBL_CLK_ENA_SC_REG, B(28),
- GLBL_CLK_STATE_REG, 28, 0x4D7B),
+ GLBL_CLK_STATE_REG, HALT_VOTED, 28, 0x4D7B),
CLK_GLBL(SPI_P, GLBL_CLK_ENA_2_SC_REG, B(10),
- GLBL_CLK_STATE_2_REG, 10, 0x18),
+ GLBL_CLK_STATE_2_REG, HALT_VOTED, 10, 0x18),
CLK_GLBL(TSIF_P, GLBL_CLK_ENA_SC_REG, B(18),
- GLBL_CLK_STATE_REG, 18, 0x4D65),
+ GLBL_CLK_STATE_REG, HALT_VOTED, 18, 0x4D65),
CLK_GLBL(UART1DM_P, GLBL_CLK_ENA_SC_REG, B(17),
- GLBL_CLK_STATE_REG, 17, 0x4D5C),
+ GLBL_CLK_STATE_REG, HALT_VOTED, 17, 0x4D5C),
CLK_GLBL(UART2DM_P, GLBL_CLK_ENA_SC_REG, B(26),
- GLBL_CLK_STATE_REG, 26, 0x4D7E),
+ GLBL_CLK_STATE_REG, HALT_VOTED, 26, 0x4D7E),
CLK_GLBL(USB_HS2_P, GLBL_CLK_ENA_2_SC_REG, B(8),
- GLBL_CLK_STATE_2_REG, 8, 0x08),
+ GLBL_CLK_STATE_2_REG, HALT_VOTED, 8, 0x08),
CLK_GLBL(USB_HS3_P, GLBL_CLK_ENA_2_SC_REG, B(9),
- GLBL_CLK_STATE_2_REG, 9, 0x10),
+ GLBL_CLK_STATE_2_REG, HALT_VOTED, 9, 0x10),
CLK_GLBL(USB_HS_P, GLBL_CLK_ENA_SC_REG, B(25),
- GLBL_CLK_STATE_REG, 25, 0x4D58),
+ GLBL_CLK_STATE_REG, HALT_VOTED, 25, 0x4D58),
CLK_GLBL(VFE_P, GLBL_CLK_ENA_2_SC_REG, B(27),
- GLBL_CLK_STATE_2_REG, 27, 0x4D55),
+ GLBL_CLK_STATE_2_REG, HALT_VOTED, 27, 0x4D55),

/* AXI bridge clocks. */
CLK_BRIDGE(AXI_LI_APPS, GLBL_CLK_ENA_SC_REG, B(2), GLBL_ROOT,
- GLBL_CLK_STATE_REG, 2, 0x4900),
+ GLBL_CLK_STATE_REG, HALT_VOTED, 2, 0x4900),
CLK_BRIDGE(AXI_LI_ADSP_A, GLBL_CLK_ENA_2_SC_REG, B(14), AXI_LI_APPS,
- GLBL_CLK_STATE_2_REG, 14, 0x6400),
+ GLBL_CLK_STATE_2_REG, HALT_VOTED, 14, 0x6400),
CLK_BRIDGE(AXI_LI_JPEG, GLBL_CLK_ENA_2_SC_REG, B(19), AXI_LI_APPS,
- GLBL_CLK_STATE_2_REG, 19, 0x4E00),
+ GLBL_CLK_STATE_2_REG, HALT_VOTED, 19, 0x4E00),
CLK_BRIDGE(AXI_LI_VFE, GLBL_CLK_ENA_SC_REG, B(23), AXI_LI_APPS,
- GLBL_CLK_STATE_REG, 23, 0x5B00),
+ GLBL_CLK_STATE_REG, HALT_VOTED, 23, 0x5B00),
CLK_BRIDGE(AXI_MDP, GLBL_CLK_ENA_2_SC_REG, B(29), AXI_LI_APPS,
- GLBL_CLK_STATE_2_REG, 29, 0x6B00),
+ GLBL_CLK_STATE_2_REG, HALT_VOTED, 29, 0x6B00),

CLK_BRIDGE(AXI_IMEM, GLBL_CLK_ENA_2_SC_REG, B(18), GLBL_ROOT,
- GLBL_CLK_STATE_2_REG, 18, 0x4B00),
+ GLBL_CLK_STATE_2_REG, HALT_VOTED, 18, 0x4B00),

CLK_BRIDGE(AXI_LI_VG, GLBL_CLK_ENA_SC_REG, B(3), GLBL_ROOT,
- GLBL_CLK_STATE_REG, 3, 0x4700),
+ GLBL_CLK_STATE_REG, HALT_VOTED, 3, 0x4700),
CLK_BRIDGE(AXI_GRP_2D, GLBL_CLK_ENA_SC_REG, B(21), AXI_LI_VG,
- GLBL_CLK_STATE_REG, 21, 0x5900),
+ GLBL_CLK_STATE_REG, HALT_VOTED, 21, 0x5900),
CLK_BRIDGE(AXI_LI_GRP, GLBL_CLK_ENA_SC_REG, B(22), AXI_LI_VG,
- GLBL_CLK_STATE_REG, 22, 0x5A00),
+ GLBL_CLK_STATE_REG, HALT_VOTED, 22, 0x5A00),
CLK_BRIDGE(AXI_MFC, GLBL_CLK_ENA_2_SC_REG, B(20), AXI_LI_VG,
- GLBL_CLK_STATE_2_REG, 20, 0x6A00),
+ GLBL_CLK_STATE_2_REG, HALT_VOTED, 20, 0x6A00),
CLK_BRIDGE(AXI_ROTATOR, GLBL_CLK_ENA_2_SC_REG, B(22), AXI_LI_VG,
- GLBL_CLK_STATE_2_REG, 22, 0x4300),
+ GLBL_CLK_STATE_2_REG, HALT_VOTED, 22, 0x4300),
CLK_BRIDGE(AXI_VPE, GLBL_CLK_ENA_2_SC_REG, B(21), AXI_LI_VG,
- GLBL_CLK_STATE_2_REG, 21, 0x6700),
-};
-
-static DEFINE_SPINLOCK(clock_reg_lock);
-static DEFINE_SPINLOCK(pll_vote_lock);
-
-enum {
- TCXO,
- LPXO,
- NUM_XO
+ GLBL_CLK_STATE_2_REG, HALT_VOTED, 21, 0x6700),
};
-static unsigned xo_votes[NUM_XO]; /* Tracks the number of users for each XO */
-
-/* Map PLLs to which XO they use */
-static const unsigned pll_to_xo[] = {
- [PLL_0] = TCXO,
- [PLL_1] = TCXO,
- [PLL_2] = TCXO,
- [PLL_3] = LPXO,
- [PLL_4] = LPXO,
- [PLL_5] = TCXO,
- [PLL_6] = TCXO,
-};
-
-static void vote_for_xo(unsigned xo)
-{
- BUG_ON(xo >= NUM_XO);
-
- if (!xo_votes[xo]) {
- int enable = 1;
- unsigned p_xo = xo;
- msm_proc_comm(PCOM_CLKCTL_RPC_SRC_REQUEST, &p_xo, &enable);
- }
- xo_votes[xo]++;
-}
-
-static void unvote_for_xo(unsigned xo)
-{
- BUG_ON(xo >= NUM_XO);

- if (xo_votes[xo]) {
- xo_votes[xo]--;
- } else {
- pr_warning("%s: Reference count mismatch!\n", __func__);
- return;
- }
-
- if (xo_votes[xo] == 0) {
- int enable = 0;
- msm_proc_comm(PCOM_CLKCTL_RPC_SRC_REQUEST, &xo, &enable);
- }
-}
-
-#define PLL_ACTIVE_MASK B(16)
-void pll_enable(uint32_t pll)
-{
- uint32_t reg_val;
- unsigned long flags;
-
- BUG_ON(pll >= NUM_PLL);
-
- spin_lock_irqsave(&pll_vote_lock, flags);
- if (!pll_count[pll]) {
- vote_for_xo(pll_to_xo[pll]);
- reg_val = readl(PLL_ENA_REG);
- reg_val |= (1 << pll);
- writel(reg_val, PLL_ENA_REG);
- }
- pll_count[pll]++;
- spin_unlock_irqrestore(&pll_vote_lock, flags);
-
- /* Wait until PLL is enabled. */
- while ((readl(pll_status_addr[pll]) & PLL_ACTIVE_MASK) == 0)
- cpu_relax();
-}
-
-void pll_disable(uint32_t pll)
-{
- uint32_t reg_val;
- unsigned long flags;
-
- BUG_ON(pll >= NUM_PLL);
-
- spin_lock_irqsave(&pll_vote_lock, flags);
- if (pll_count[pll]) {
- pll_count[pll]--;
- } else {
- pr_warning("Reference count mismatch in PLL disable!\n");
- goto out;
- }
-
- if (pll_count[pll] == 0) {
- reg_val = readl(PLL_ENA_REG);
- reg_val &= ~(1 << pll);
- writel(reg_val, PLL_ENA_REG);
- unvote_for_xo(pll_to_xo[pll]);
- }
-out:
- spin_unlock_irqrestore(&pll_vote_lock, flags);
-}
-
-static void src_enable(uint32_t src)
-{
- switch (src) {
- case SRC_NONE:
- /*
- * SRC_NONE is used as a placeholder for some freqencies that
- * don't have any direct PLL dependency. Instead they source
- * off an external/internal clock which takes care of any
- * PLL or XO dependency.
- */
- break;
- case SRC_TCXO:
- vote_for_xo(TCXO);
- break;
- case SRC_AXI:
- case SRC_LPXO:
- /*
- * AXI could use LPXO or TCXO. Map it to LPXO to make sure
- * there is at least once XO available for the AXI (LPXO is
- * the lower powered one so just use that).
- */
- vote_for_xo(LPXO);
- break;
- default:
- pll_enable(src_pll_tbl[src]);
- break;
- }
-}
-
-static void src_disable(uint32_t src)
-{
- switch (src) {
- case SRC_NONE:
- /*
- * SRC_NONE is used as a placeholder for some freqencies that
- * don't have any direct PLL dependency. Instead they source
- * off an external/internal clock which takes care of any
- * PLL or XO dependency.
- */
- break;
- case SRC_TCXO:
- unvote_for_xo(TCXO);
- break;
- case SRC_AXI:
- case SRC_LPXO:
- /*
- * AXI could use LPXO or TCXO. Map it to LPXO to make sure
- * there is at least once XO available for the AXI (LPXO is
- * the lower powered one so just use that).
- */
- unvote_for_xo(LPXO);
- break;
- default:
- pll_disable(src_pll_tbl[src]);
- break;
- }
-}
-
-static unsigned msmc1_votes[MSMC1_END];
-static unsigned msmc1_level;
+/*
+ * SoC-specific functions required by clock-local driver
+ */

-static int update_msmc1(void)
+/* Update the sys_vdd voltage given a level. */
+int soc_update_sys_vdd(enum sys_vdd_level level)
{
- int err, target, mvolts;
-
- if (msmc1_votes[HIGH])
- target = 1200;
- else if (msmc1_votes[NOMINAL])
- target = 1100;
- else
- target = 1000;
-
- if (target == msmc1_level)
- return 0;
-
- mvolts = target;
- err = msm_proc_comm(PCOM_CLKCTL_RPC_MIN_MSMC1, &mvolts, NULL);
- if (err)
+ int rc, target_mv;
+ static const int mv[NUM_SYS_VDD_LEVELS] = {
+ [NONE...LOW] = 1000,
+ [NOMINAL] = 1100,
+ [HIGH] = 1200,
+ };
+
+ target_mv = mv[level];
+ rc = msm_proc_comm(PCOM_CLKCTL_RPC_MIN_MSMC1, &target_mv, NULL);
+ if (rc)
goto out;
-
- if (mvolts) {
- err = -EINVAL;
+ if (target_mv) {
+ rc = -EINVAL;
goto out;
}
- msmc1_level = target;
out:
- return err;
-}
-
-static void unvote_msmc1(unsigned level)
-{
- if (level >= ARRAY_SIZE(msmc1_votes))
- return;
-
- if (msmc1_votes[level]) {
- msmc1_votes[level]--;
- } else {
- pr_warning("%s: Reference counts are incorrect\n", __func__);
- return;
- }
-
- update_msmc1();
-}
-
-static int vote_msmc1(unsigned level)
-{
- int ret;
-
- if (level >= ARRAY_SIZE(msmc1_votes))
- return 0;
-
- msmc1_votes[level]++;
- ret = update_msmc1();
- if (ret)
- msmc1_votes[level]--;
-
- return ret;
-}
-
-/*
- * SoC specific register-based control of clocks.
- */
-static int _soc_clk_enable(unsigned id)
-{
- struct clk_local *t = &clk_local_tbl[id];
- void *ns_reg = t->ns_reg;
- uint32_t reg_val = 0;
-
- WARN((t->type != NORATE) && (t->current_freq == &dummy_freq),
- "Attempting to enable clock %d before setting its rate. "
- "Set the rate first!\n", id);
-
- reg_val = readl(ns_reg);
- if (t->type == MND) {
- /* mode can be either 0 or 1. So the R-value of the
- * expression will evaluate to MNCNTR_EN_MASK or 0. This
- * avoids the need for a "if(mode == 1)". A "&" will not work
- * here. */
- reg_val |= (MNCNTR_EN_MASK * t->current_freq->mode);
- writel(reg_val, ns_reg);
- }
- if (t->root_en_mask) {
- reg_val |= t->root_en_mask;
- writel(reg_val, ns_reg);
- }
- if (t->br_en_mask) {
- reg_val |= t->br_en_mask;
- writel(reg_val, ns_reg);
- }
- if (t->halt_reg) {
- uint32_t halted, count = 0;
-
- /* Wait for the halt bit to clear, but timeout after 100usecs
- * since the halt bit may be buggy. */
- while ((halted = readl(t->halt_reg) & BIT(t->halt_mask))
- && count++ < 100)
- udelay(1);
- if (halted)
- pr_warning("%s: clock %d never turned on\n", __func__,
- id);
- }
- return 0;
-}
-
-static void _soc_clk_disable(unsigned id)
-{
- struct clk_local *t = &clk_local_tbl[id];
- void *ns_reg = t->ns_reg;
- uint32_t reg_val = 0;
-
- reg_val = readl(ns_reg);
-
- if (t->br_en_mask) {
- reg_val &= ~(t->br_en_mask);
- writel(reg_val, ns_reg);
- }
- if (t->halt_reg) {
- uint32_t halted, count = 0;
-
- /* Wait for the halt bit to be set, but timeout after 100usecs
- * since the halt bit may be buggy. */
- while (!(halted = readl(t->halt_reg) & BIT(t->halt_mask))
- && count++ < 100)
- udelay(1);
- if (!halted)
- pr_warning("%s: clock %d never turned off\n", __func__,
- id);
- }
- if (t->root_en_mask) {
- reg_val &= ~(t->root_en_mask);
- writel(reg_val, ns_reg);
- }
- if (t->type == MND) {
- reg_val &= ~MNCNTR_EN_MASK;
- writel(reg_val, ns_reg);
- }
+ return rc;
}

-static int soc_clk_enable_nolock(unsigned id)
-{
- struct clk_local *t = &clk_local_tbl[id];
- int ret = 0;
-
- if (!t->count) {
- ret = vote_msmc1(t->current_freq->msmc1);
- if (ret)
- return ret;
- if (t->parent != C(NONE)) {
- ret = soc_clk_enable_nolock(t->parent);
- if (ret)
- return ret;
- }
- src_enable(t->current_freq->src);
- ret = _soc_clk_enable(id);
- }
- t->count++;
-
- return ret;
-}
-
-static void soc_clk_disable_nolock(unsigned id)
-{
- struct clk_local *t = &clk_local_tbl[id];
-
- if (!t->count) {
- pr_warning("Reference count mismatch in clock disable!\n");
- return;
- }
- if (t->count)
- t->count--;
- if (t->count == 0) {
- _soc_clk_disable(id);
- src_disable(t->current_freq->src);
- unvote_msmc1(t->current_freq->msmc1);
- if (t->parent != C(NONE))
- soc_clk_disable_nolock(t->parent);
- }
-
- return;
-}
-
-static int update_pwr_rail(unsigned id, int enable)
+/* Enable/disable a power rail associated with a clock. */
+int soc_set_pwr_rail(unsigned id, int enable)
{
/* TODO: Implement internal power rail control */
return 0;
}

-static int soc_clk_enable(unsigned id)
-{
- int ret = 0;
- unsigned long flags;
-
- spin_lock_irqsave(&clock_reg_lock, flags);
- ret = soc_clk_enable_nolock(id);
- if (ret)
- goto unlock;
- /*
- * The modem might modify the register bits for the clock branch when
- * the rail is enabled/disabled, so enable the rail inside the lock
- * instead of outside it.
- */
- ret = update_pwr_rail(id, 1);
- if (ret)
- soc_clk_disable_nolock(id);
-unlock:
- spin_unlock_irqrestore(&clock_reg_lock, flags);
-
- return ret;
-}
-
-static void soc_clk_disable(unsigned id)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&clock_reg_lock, flags);
- update_pwr_rail(id, 0);
- soc_clk_disable_nolock(id);
- spin_unlock_irqrestore(&clock_reg_lock, flags);
-}
-
-static void soc_clk_auto_off(unsigned id)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&clock_reg_lock, flags);
- _soc_clk_disable(id);
- spin_unlock_irqrestore(&clock_reg_lock, flags);
-}
-
-static long soc_clk_round_rate(unsigned id, unsigned rate)
-{
- struct clk_local *t = &clk_local_tbl[id];
- const struct clk_freq_tbl *f;
-
- if (t->type != MND && t->type != BASIC)
- return -EINVAL;
-
- for (f = t->freq_tbl; f->freq_hz != FREQ_END; f++)
- if (f->freq_hz >= rate)
- return f->freq_hz;
-
- return -EPERM;
-}
-
-static int soc_clk_set_rate(unsigned id, unsigned rate)
-{
- struct clk_local *t = &clk_local_tbl[id];
- const struct clk_freq_tbl *cf;
- const struct clk_freq_tbl *nf;
- uint32_t *chld = t->children;
- void *ns_reg = t->ns_reg;
- void *md_reg = t->md_reg;
- uint32_t reg_val = 0;
- int i, ret = 0;
- unsigned long flags;
- long rounded;
-
- rounded = soc_clk_round_rate(id, rate);
- if (rounded != rate)
- pr_warning("Use clk_round_rate() before clk_set_rate() with "
- "clock %u\n", id);
- rate = rounded;
-
- if (t->type != MND && t->type != BASIC)
- return -EPERM;
-
- spin_lock_irqsave(&clock_reg_lock, flags);
- cf = t->current_freq;
-
- if (rate == cf->freq_hz)
- goto release_lock;
-
- for (nf = t->freq_tbl; nf->freq_hz != FREQ_END; nf++)
- if (nf->freq_hz == rate)
- break;
-
- if (nf->freq_hz == FREQ_END) {
- ret = -EINVAL;
- goto release_lock;
- }
-
- if (t->freq_mask == 0) {
- t->current_freq = nf;
- goto release_lock;
- }
-
- /* Disable all branches before changing rate to prevent jitter. */
- for (i = 0; chld && chld[i] != C(NONE); i++) {
- struct clk_local *ch = &clk_local_tbl[chld[i]];
- /* Don't bother turning off if it is already off.
- * Checking ch->count is cheaper (cache) than reading and
- * writing to a register (uncached/unbuffered). */
- if (ch->count) {
- reg_val = readl(ch->ns_reg);
- reg_val &= ~(ch->br_en_mask);
- writel(reg_val, ch->ns_reg);
- }
- }
-
- if (t->count) {
- _soc_clk_disable(id);
-
- ret = vote_msmc1(nf->msmc1);
- if (ret)
- goto msmc1_err;
- /* Turn on PLL of the new freq. */
- src_enable(nf->src);
- }
-
- /* Some clocks share the same register, so must be careful when
- * assuming a register doesn't need to be re-read. */
- reg_val = readl(ns_reg);
- if (t->type == MND) {
- reg_val |= MNCNTR_RST_MASK;
- writel(reg_val, ns_reg);
- /* TODO: Currently writing 0's into reserved bits for 8-bit
- * MND. Can be avoided by adding md_mask. */
- if (nf->mode)
- writel(nf->md_val, md_reg);
- reg_val &= ~MNCNTR_MODE_MASK;
- reg_val |= (MNCNTR_MODE * nf->mode);
- }
- reg_val &= ~(t->freq_mask);
- reg_val |= nf->ns_val;
- writel(reg_val, ns_reg);
-
- if (t->type == MND) {
- reg_val &= ~MNCNTR_RST_MASK;
- writel(reg_val, ns_reg);
- }
-
- if (t->count) {
- /* Turn off PLL of the old freq. */
- src_disable(cf->src);
- unvote_msmc1(cf->msmc1);
- }
-
- /* Current freq must be updated before _soc_clk_enable() is called to
- * make sure the MNCNTR_E bit is set correctly. */
- t->current_freq = nf;
-
-msmc1_err:
- if (t->count)
- _soc_clk_enable(id);
- /* Enable only branches that were ON before. */
- for (i = 0; chld && chld[i] != C(NONE); i++) {
- struct clk_local *ch = &clk_local_tbl[chld[i]];
- if (ch->count) {
- reg_val = readl(ch->ns_reg);
- reg_val |= ch->br_en_mask;
- writel(reg_val, ch->ns_reg);
- }
- }
-
-release_lock:
- spin_unlock_irqrestore(&clock_reg_lock, flags);
- return ret;
-}
-
-static int soc_clk_set_min_rate(unsigned id, unsigned rate)
-{
- long rounded = soc_clk_round_rate(id, rate);
- return soc_clk_set_rate(id, rounded);
-}
-
-static int soc_clk_set_max_rate(unsigned id, unsigned rate)
-{
- return -EPERM;
-}
-
-static int soc_clk_set_flags(unsigned id, unsigned clk_flags)
+/* Implementation for clk_set_flags(). */
+int soc_clk_set_flags(unsigned id, unsigned clk_flags)
{
uint32_t regval, ret = 0;
unsigned long flags;

- spin_lock_irqsave(&clock_reg_lock, flags);
+ spin_lock_irqsave(&local_clock_reg_lock, flags);
switch (id) {
case C(VFE):
regval = readl(CAM_VFE_NS_REG);
@@ -1261,50 +713,102 @@ static int soc_clk_set_flags(unsigned id, unsigned clk_flags)
default:
ret = -EPERM;
}
- spin_unlock_irqrestore(&clock_reg_lock, flags);
+ spin_unlock_irqrestore(&local_clock_reg_lock, flags);

return ret;
}

-static unsigned soc_clk_get_rate(unsigned id)
+/* Enable function for TCXO and LPXO. */
+static int soc_xo_enable(unsigned src, unsigned enable)
{
- struct clk_local *t = &clk_local_tbl[id];
- unsigned long flags;
- unsigned ret = 0;
+ unsigned pcom_xo_id;

- if (t->type == NORATE)
+ if (src == TCXO)
+ pcom_xo_id = 0;
+ else if (src == LPXO)
+ pcom_xo_id = 1;
+ else
return 0;

- spin_lock_irqsave(&clock_reg_lock, flags);
- ret = t->current_freq->freq_hz;
- spin_unlock_irqrestore(&clock_reg_lock, flags);
-
- /* Return 0 if the rate has never been set. Might not be correct,
- * but it's good enough. */
- if (ret == FREQ_END)
- ret = 0;
-
- return ret;
+ return msm_proc_comm(PCOM_CLKCTL_RPC_SRC_REQUEST, &pcom_xo_id, &enable);
}

-static unsigned soc_clk_is_enabled(unsigned id)
+/* Enable function for PLLs. */
+static int soc_pll_enable(unsigned src, unsigned enable)
{
- return !!(clk_local_tbl[id].count);
-}
+ static const struct pll_ena {
+ uint32_t *const reg;
+ const uint32_t mask;
+ } soc_pll_ena[NUM_SRC] = {
+ [PLL_0] = {PLL_ENA_REG, B(0)},
+ [PLL_1] = {PLL_ENA_REG, B(1)},
+ [PLL_2] = {PLL_ENA_REG, B(2)},
+ [PLL_3] = {PLL_ENA_REG, B(3)},
+ [PLL_4] = {PLL_ENA_REG, B(4)},
+ [PLL_5] = {PLL_ENA_REG, B(5)},
+ [PLL_6] = {PLL_ENA_REG, B(6)},
+ };
+ uint32_t *const soc_pll_status_reg[NUM_SRC] = {
+
+ [PLL_0] = PLL0_STATUS_BASE_REG,
+ [PLL_1] = PLL1_STATUS_BASE_REG,
+ [PLL_2] = PLL2_STATUS_BASE_REG,
+ [PLL_3] = PLL3_STATUS_BASE_REG,
+ [PLL_4] = PLL4_STATUS_BASE_REG,
+ [PLL_5] = PLL5_STATUS_BASE_REG,
+ [PLL_6] = PLL6_STATUS_BASE_REG,
+ };
+ uint32_t reg_val;

+ reg_val = readl(soc_pll_ena[src].reg);

-struct clk_ops clk_ops_7x30 = {
- .enable = soc_clk_enable,
- .disable = soc_clk_disable,
- .auto_off = soc_clk_auto_off,
- .set_rate = soc_clk_set_rate,
- .set_min_rate = soc_clk_set_min_rate,
- .set_max_rate = soc_clk_set_max_rate,
- .reset = pc_clk_reset,
- .set_flags = soc_clk_set_flags,
- .get_rate = soc_clk_get_rate,
- .is_enabled = soc_clk_is_enabled,
- .round_rate = soc_clk_round_rate,
+ if (enable)
+ reg_val |= soc_pll_ena[src].mask;
+ else
+ reg_val &= ~(soc_pll_ena[src].mask);
+
+ writel(reg_val, soc_pll_ena[src].reg);
+
+ if (enable) {
+ /* Wait until PLL is enabled */
+ while ((readl(soc_pll_status_reg[src]) & B(16)) == 0)
+ cpu_relax();
+ }
+
+ return 0;
+}
+
+struct clk_source soc_clk_sources[NUM_SRC] = {
+ [TCXO] = { .enable_func = soc_xo_enable,
+ .par = SRC_NONE,
+ },
+ [LPXO] = { .enable_func = soc_xo_enable,
+ .par = SRC_NONE,
+ },
+ [AXI] = { .enable_func = NULL,
+ .par = LPXO,
+ },
+ [PLL_0] = { .enable_func = soc_pll_enable,
+ .par = TCXO,
+ },
+ [PLL_1] = { .enable_func = soc_pll_enable,
+ .par = TCXO,
+ },
+ [PLL_2] = { .enable_func = soc_pll_enable,
+ .par = TCXO,
+ },
+ [PLL_3] = { .enable_func = soc_pll_enable,
+ .par = LPXO,
+ },
+ [PLL_4] = { .enable_func = soc_pll_enable,
+ .par = LPXO,
+ },
+ [PLL_5] = { .enable_func = soc_pll_enable,
+ .par = TCXO,
+ },
+ [PLL_6] = { .enable_func = soc_pll_enable,
+ .par = TCXO,
+ },
};

/*
@@ -1454,6 +958,22 @@ static bool __init clk_is_local(uint32_t id)
return *reg & bit;
}

+/* SoC-specific clk_ops initialization. */
+void __init msm_clk_soc_set_ops(struct clk *clk)
+{
+ if (!clk->ops) {
+ if (clk_is_local(clk->id))
+ clk->ops = &soc_clk_ops_7x30;
+ else {
+ clk->ops = &clk_ops_pcom;
+ clk->id = clk->remote_id;
+ }
+ }
+}
+
+/*
+ * Miscellaneous clock register initializations
+ */
static const struct reg_init {
const void __iomem *reg;
uint32_t mask;
@@ -1490,21 +1010,7 @@ static const struct reg_init {
{USBH3_NS_REG, B(6), B(6)},
};

-/* SoC-specific clk_ops initialization. */
-void __init msm_clk_soc_set_ops(struct clk *clk)
-{
- if (!clk->ops) {
- if (clk_is_local(clk->id))
- clk->ops = &clk_ops_7x30;
- else {
- clk->ops = &clk_ops_pcom;
- clk->id = clk->remote_id;
- }
- }
-}
-
-#define set_1rate(clk) \
- soc_clk_set_rate(C(clk), clk_local_tbl[C(clk)].freq_tbl->freq_hz)
+/* Local clock driver initialization. */
void __init msm_clk_soc_init(void)
{
int i;
@@ -1522,10 +1028,10 @@ void __init msm_clk_soc_init(void)
* USB HS core clocks. */
for (i = 0; chld_usb_src[i] != C(NONE); i++)
if (clk_is_local(chld_usb_src[i]))
- _soc_clk_disable(chld_usb_src[i]);
+ local_clk_disable_reg(chld_usb_src[i]);

if (clk_is_local(C(USB_HS_SRC)))
- soc_clk_set_rate(C(USB_HS_SRC), clk_tbl_usb[0].freq_hz);
+ local_clk_set_rate(C(USB_HS_SRC), clk_tbl_usb[0].freq_hz);

for (i = 0; i < ARRAY_SIZE(ri_list); i++) {
val = readl(ri_list[i].reg);
@@ -1546,5 +1052,23 @@ void __init msm_clk_soc_init(void)
set_1rate(GLBL_ROOT);

/* Sync the GRP2D clock to AXI */
- soc_clk_set_rate(C(GRP_2D), 1);
+ local_clk_set_rate(C(GRP_2D), 1);
}
+
+
+/*
+ * Clock operation handler registration
+ */
+struct clk_ops soc_clk_ops_7x30 = {
+ .enable = local_clk_enable,
+ .disable = local_clk_disable,
+ .auto_off = local_clk_auto_off,
+ .set_rate = local_clk_set_rate,
+ .set_min_rate = local_clk_set_min_rate,
+ .set_max_rate = local_clk_set_max_rate,
+ .get_rate = local_clk_get_rate,
+ .is_enabled = local_clk_is_enabled,
+ .round_rate = local_clk_round_rate,
+ .reset = pc_clk_reset,
+ .set_flags = soc_clk_set_flags,
+};
diff --git a/arch/arm/mach-msm/clock-7x30.h b/arch/arm/mach-msm/clock-7x30.h
index d41acb7..01c49c7 100644
--- a/arch/arm/mach-msm/clock-7x30.h
+++ b/arch/arm/mach-msm/clock-7x30.h
@@ -31,116 +31,112 @@
#define __ARCH_ARM_MACH_MSM_CLOCK_7X30_H

enum {
- L_7X30_NONE_CLK = -1,
- L_7X30_ADM_CLK,
- L_7X30_ADM_P_CLK,
- L_7X30_CE_CLK,
- L_7X30_I2C_CLK,
- L_7X30_I2C_2_CLK,
- L_7X30_QUP_I2C_CLK,
- L_7X30_UART1DM_CLK,
- L_7X30_UART1DM_P_CLK,
- L_7X30_UART2DM_CLK,
- L_7X30_UART2DM_P_CLK,
- L_7X30_EMDH_CLK,
- L_7X30_EMDH_P_CLK,
- L_7X30_PMDH_CLK,
- L_7X30_PMDH_P_CLK,
- L_7X30_GRP_2D_CLK,
- L_7X30_GRP_2D_P_CLK,
- L_7X30_GRP_3D_SRC_CLK,
- L_7X30_GRP_3D_CLK,
- L_7X30_GRP_3D_P_CLK,
- L_7X30_IMEM_CLK,
- L_7X30_SDC1_CLK,
- L_7X30_SDC1_P_CLK,
- L_7X30_SDC2_CLK,
- L_7X30_SDC2_P_CLK,
- L_7X30_SDC3_CLK,
- L_7X30_SDC3_P_CLK,
- L_7X30_SDC4_CLK,
- L_7X30_SDC4_P_CLK,
- L_7X30_MDP_CLK,
- L_7X30_MDP_P_CLK,
- L_7X30_MDP_LCDC_PCLK_CLK,
- L_7X30_MDP_LCDC_PAD_PCLK_CLK,
- L_7X30_MDP_VSYNC_CLK,
- L_7X30_MI2S_CODEC_RX_M_CLK,
- L_7X30_MI2S_CODEC_RX_S_CLK,
- L_7X30_MI2S_CODEC_TX_M_CLK,
- L_7X30_MI2S_CODEC_TX_S_CLK,
- L_7X30_MI2S_M_CLK,
- L_7X30_MI2S_S_CLK,
- L_7X30_LPA_CODEC_CLK,
- L_7X30_LPA_CORE_CLK,
- L_7X30_LPA_P_CLK,
- L_7X30_MIDI_CLK,
- L_7X30_MDC_CLK,
- L_7X30_ROTATOR_IMEM_CLK,
- L_7X30_ROTATOR_P_CLK,
- L_7X30_SDAC_M_CLK,
- L_7X30_SDAC_CLK,
- L_7X30_UART1_CLK,
- L_7X30_UART2_CLK,
- L_7X30_UART3_CLK,
- L_7X30_TV_CLK,
- L_7X30_TV_DAC_CLK,
- L_7X30_TV_ENC_CLK,
- L_7X30_HDMI_CLK,
- L_7X30_TSIF_REF_CLK,
- L_7X30_TSIF_P_CLK,
- L_7X30_USB_HS_SRC_CLK,
- L_7X30_USB_HS_CLK,
- L_7X30_USB_HS_CORE_CLK,
- L_7X30_USB_HS_P_CLK,
- L_7X30_USB_HS2_CLK,
- L_7X30_USB_HS2_CORE_CLK,
- L_7X30_USB_HS2_P_CLK,
- L_7X30_USB_HS3_CLK,
- L_7X30_USB_HS3_CORE_CLK,
- L_7X30_USB_HS3_P_CLK,
- L_7X30_VFE_CLK,
- L_7X30_VFE_P_CLK,
- L_7X30_VFE_MDC_CLK,
- L_7X30_VFE_CAMIF_CLK,
- L_7X30_CAMIF_PAD_P_CLK,
- L_7X30_CAM_M_CLK,
- L_7X30_JPEG_CLK,
- L_7X30_JPEG_P_CLK,
- L_7X30_VPE_CLK,
- L_7X30_MFC_CLK,
- L_7X30_MFC_DIV2_CLK,
- L_7X30_MFC_P_CLK,
- L_7X30_SPI_CLK,
- L_7X30_SPI_P_CLK,
- L_7X30_CSI0_CLK,
- L_7X30_CSI0_VFE_CLK,
- L_7X30_CSI0_P_CLK,
- L_7X30_CSI1_CLK,
- L_7X30_CSI1_VFE_CLK,
- L_7X30_CSI1_P_CLK,
- L_7X30_GLBL_ROOT_CLK,
+ L_ADM_CLK,
+ L_ADM_P_CLK,
+ L_CE_CLK,
+ L_I2C_CLK,
+ L_I2C_2_CLK,
+ L_QUP_I2C_CLK,
+ L_UART1DM_CLK,
+ L_UART1DM_P_CLK,
+ L_UART2DM_CLK,
+ L_UART2DM_P_CLK,
+ L_EMDH_CLK,
+ L_EMDH_P_CLK,
+ L_PMDH_CLK,
+ L_PMDH_P_CLK,
+ L_GRP_2D_CLK,
+ L_GRP_2D_P_CLK,
+ L_GRP_3D_SRC_CLK,
+ L_GRP_3D_CLK,
+ L_GRP_3D_P_CLK,
+ L_IMEM_CLK,
+ L_SDC1_CLK,
+ L_SDC1_P_CLK,
+ L_SDC2_CLK,
+ L_SDC2_P_CLK,
+ L_SDC3_CLK,
+ L_SDC3_P_CLK,
+ L_SDC4_CLK,
+ L_SDC4_P_CLK,
+ L_MDP_CLK,
+ L_MDP_P_CLK,
+ L_MDP_LCDC_PCLK_CLK,
+ L_MDP_LCDC_PAD_PCLK_CLK,
+ L_MDP_VSYNC_CLK,
+ L_MI2S_CODEC_RX_M_CLK,
+ L_MI2S_CODEC_RX_S_CLK,
+ L_MI2S_CODEC_TX_M_CLK,
+ L_MI2S_CODEC_TX_S_CLK,
+ L_MI2S_M_CLK,
+ L_MI2S_S_CLK,
+ L_LPA_CODEC_CLK,
+ L_LPA_CORE_CLK,
+ L_LPA_P_CLK,
+ L_MIDI_CLK,
+ L_MDC_CLK,
+ L_ROTATOR_IMEM_CLK,
+ L_ROTATOR_P_CLK,
+ L_SDAC_M_CLK,
+ L_SDAC_CLK,
+ L_UART1_CLK,
+ L_UART2_CLK,
+ L_UART3_CLK,
+ L_TV_CLK,
+ L_TV_DAC_CLK,
+ L_TV_ENC_CLK,
+ L_HDMI_CLK,
+ L_TSIF_REF_CLK,
+ L_TSIF_P_CLK,
+ L_USB_HS_SRC_CLK,
+ L_USB_HS_CLK,
+ L_USB_HS_CORE_CLK,
+ L_USB_HS_P_CLK,
+ L_USB_HS2_CLK,
+ L_USB_HS2_CORE_CLK,
+ L_USB_HS2_P_CLK,
+ L_USB_HS3_CLK,
+ L_USB_HS3_CORE_CLK,
+ L_USB_HS3_P_CLK,
+ L_VFE_CLK,
+ L_VFE_P_CLK,
+ L_VFE_MDC_CLK,
+ L_VFE_CAMIF_CLK,
+ L_CAMIF_PAD_P_CLK,
+ L_CAM_M_CLK,
+ L_JPEG_CLK,
+ L_JPEG_P_CLK,
+ L_VPE_CLK,
+ L_MFC_CLK,
+ L_MFC_DIV2_CLK,
+ L_MFC_P_CLK,
+ L_SPI_CLK,
+ L_SPI_P_CLK,
+ L_CSI0_CLK,
+ L_CSI0_VFE_CLK,
+ L_CSI0_P_CLK,
+ L_CSI1_CLK,
+ L_CSI1_VFE_CLK,
+ L_CSI1_P_CLK,
+ L_GLBL_ROOT_CLK,

- L_7X30_AXI_LI_VG_CLK,
- L_7X30_AXI_LI_GRP_CLK,
- L_7X30_AXI_LI_JPEG_CLK,
- L_7X30_AXI_GRP_2D_CLK,
- L_7X30_AXI_MFC_CLK,
- L_7X30_AXI_VPE_CLK,
- L_7X30_AXI_LI_VFE_CLK,
- L_7X30_AXI_LI_APPS_CLK,
- L_7X30_AXI_MDP_CLK,
- L_7X30_AXI_IMEM_CLK,
- L_7X30_AXI_LI_ADSP_A_CLK,
- L_7X30_AXI_ROTATOR_CLK,
+ L_AXI_LI_VG_CLK,
+ L_AXI_LI_GRP_CLK,
+ L_AXI_LI_JPEG_CLK,
+ L_AXI_GRP_2D_CLK,
+ L_AXI_MFC_CLK,
+ L_AXI_VPE_CLK,
+ L_AXI_LI_VFE_CLK,
+ L_AXI_LI_APPS_CLK,
+ L_AXI_MDP_CLK,
+ L_AXI_IMEM_CLK,
+ L_AXI_LI_ADSP_A_CLK,
+ L_AXI_ROTATOR_CLK,

- L_7X30_NR_CLKS
+ L_NR_CLKS
};

-void pll_enable(uint32_t pll);
-void pll_disable(uint32_t pll);
-
-enum {
+enum clk_sources {
PLL_0 = 0,
PLL_1,
PLL_2,
@@ -148,22 +144,18 @@ enum {
PLL_4,
PLL_5,
PLL_6,
- NUM_PLL
-};
-
-enum {
- LOW,
- NOMINAL,
- HIGH,
- MSMC1_END
+ AXI,
+ LPXO,
+ TCXO,
+ NUM_SRC
};

extern int internal_pwr_rail_ctl_auto(unsigned rail_id, bool enable);

-extern struct clk_ops clk_ops_7x30;
+extern struct clk_ops soc_clk_ops_7x30;
#define CLK_7X30(clk_name, clk_id, clk_dev, clk_flags) { \
.name = clk_name, \
- .id = L_7X30_##clk_id, \
+ .id = L_##clk_id, \
.remote_id = P_##clk_id, \
.flags = clk_flags, \
.dev = clk_dev, \
@@ -172,7 +164,7 @@ extern struct clk_ops clk_ops_7x30;

#define CLK_7X30S(clk_name, l_id, r_id, clk_dev, clk_flags) { \
.name = clk_name, \
- .id = L_7X30_##l_id, \
+ .id = L_##l_id, \
.remote_id = P_##r_id, \
.flags = clk_flags, \
.dev = clk_dev, \
@@ -181,11 +173,11 @@ extern struct clk_ops clk_ops_7x30;

#define CLK_7X30L(clk_name, l_id, clk_dev, clk_flags) { \
.name = clk_name, \
- .id = L_7X30_##l_id, \
+ .id = L_##l_id, \
.flags = clk_flags, \
.dev = clk_dev, \
.dbg_name = #l_id, \
- .ops = &clk_ops_7x30, \
+ .ops = &soc_clk_ops_7x30, \
}

#endif
diff --git a/arch/arm/mach-msm/clock-local.c b/arch/arm/mach-msm/clock-local.c
new file mode 100644
index 0000000..d6eb6c6
--- /dev/null
+++ b/arch/arm/mach-msm/clock-local.c
@@ -0,0 +1,679 @@
+/* Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/ctype.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <mach/msm_iomap.h>
+#include <mach/clk.h>
+
+#include "clock.h"
+#include "clock-local.h"
+
+/* When enabling/disabling a clock, check the halt bit up to this number
+ * number of times (with a 1 us delay in between) before continuing. */
+#define HALT_CHECK_MAX_LOOPS 100
+/* For clock without halt checking, wait this long after enables/disables. */
+#define HALT_CHECK_DELAY_US 10
+
+DEFINE_SPINLOCK(local_clock_reg_lock);
+struct clk_freq_tbl local_dummy_freq = F_END;
+
+#define MAX_SOURCES 20
+static int src_votes[MAX_SOURCES];
+static DEFINE_SPINLOCK(src_vote_lock);
+
+unsigned local_sys_vdd_votes[NUM_SYS_VDD_LEVELS];
+static DEFINE_SPINLOCK(sys_vdd_vote_lock);
+
+static int local_clk_enable_nolock(unsigned id);
+static int local_clk_disable_nolock(unsigned id);
+static int local_src_enable_nolock(int src);
+static int local_src_disable_nolock(int src);
+
+/*
+ * Common Set-Rate Functions
+ */
+/* For clocks with integer dividers only. */
+void set_rate_basic(struct clk_local *clk, struct clk_freq_tbl *nf)
+{
+ uint32_t reg_val;
+
+ reg_val = readl(clk->ns_reg);
+ reg_val &= ~(clk->ns_mask);
+ reg_val |= nf->ns_val;
+ writel(reg_val, clk->ns_reg);
+}
+
+/* For clocks with MND dividers. */
+void set_rate_mnd(struct clk_local *clk, struct clk_freq_tbl *nf)
+{
+ uint32_t ns_reg_val, cc_reg_val;
+
+ /* Assert MND reset. */
+ ns_reg_val = readl(clk->ns_reg);
+ ns_reg_val |= B(7);
+ writel(ns_reg_val, clk->ns_reg);
+
+ /* Program M and D values. */
+ writel(nf->md_val, clk->md_reg);
+
+ /* Program NS register. */
+ ns_reg_val &= ~(clk->ns_mask);
+ ns_reg_val |= nf->ns_val;
+ writel(ns_reg_val, clk->ns_reg);
+
+ /* If the clock has a separate CC register, program it. */
+ if (clk->ns_reg != clk->cc_reg) {
+ cc_reg_val = readl(clk->cc_reg);
+ cc_reg_val &= ~(clk->cc_mask);
+ cc_reg_val |= nf->cc_val;
+ writel(cc_reg_val, clk->cc_reg);
+ }
+
+ /* Deassert MND reset. */
+ ns_reg_val &= ~B(7);
+ writel(ns_reg_val, clk->ns_reg);
+}
+
+void set_rate_nop(struct clk_local *clk, struct clk_freq_tbl *nf)
+{
+ /* Nothing to do for fixed-rate clocks. */
+}
+
+/*
+ * SYS_VDD voting functions
+ */
+
+/* Update system voltage level given the current votes. */
+static int local_update_sys_vdd(void)
+{
+ static int cur_level = NUM_SYS_VDD_LEVELS;
+ int level, rc = 0;
+
+ if (local_sys_vdd_votes[HIGH])
+ level = HIGH;
+ else if (local_sys_vdd_votes[NOMINAL])
+ level = NOMINAL;
+ else if (local_sys_vdd_votes[LOW])
+ level = LOW;
+ else
+ level = NONE;
+
+ if (level == cur_level)
+ return rc;
+
+ rc = soc_update_sys_vdd(level);
+ if (!rc)
+ cur_level = level;
+
+ return rc;
+}
+
+/* Vote for a system voltage level. */
+int local_vote_sys_vdd(unsigned level)
+{
+ int rc = 0;
+ unsigned long flags;
+
+ /* Bounds checking. */
+ if (level >= ARRAY_SIZE(local_sys_vdd_votes))
+ return -EINVAL;
+
+ spin_lock_irqsave(&sys_vdd_vote_lock, flags);
+ local_sys_vdd_votes[level]++;
+ rc = local_update_sys_vdd();
+ if (rc)
+ local_sys_vdd_votes[level]--;
+ spin_unlock_irqrestore(&sys_vdd_vote_lock, flags);
+
+ return rc;
+}
+
+/* Remove vote for a system voltage level. */
+int local_unvote_sys_vdd(unsigned level)
+{
+ int rc = 0;
+ unsigned long flags;
+
+ /* Bounds checking. */
+ if (level >= ARRAY_SIZE(local_sys_vdd_votes))
+ return -EINVAL;
+
+ spin_lock_irqsave(&sys_vdd_vote_lock, flags);
+ if (local_sys_vdd_votes[level])
+ local_sys_vdd_votes[level]--;
+ else {
+ pr_warning("%s: Reference counts are incorrect for level %d!\n",
+ __func__, level);
+ goto out;
+ }
+
+ rc = local_update_sys_vdd();
+ if (rc)
+ local_sys_vdd_votes[level]++;
+out:
+ spin_unlock_irqrestore(&sys_vdd_vote_lock, flags);
+ return rc;
+}
+
+/*
+ * Clock source (PLL/XO) control functions
+ */
+
+/* Enable clock source without taking the lock. */
+static int local_src_enable_nolock(int src)
+{
+ int rc = 0;
+
+ if (!src_votes[src]) {
+ if (soc_clk_sources[src].par != SRC_NONE)
+ rc = local_src_enable_nolock(soc_clk_sources[src].par);
+ if (rc)
+ goto err_par;
+ /* Perform source-specific enable operations. */
+ if (soc_clk_sources[src].enable_func)
+ rc = soc_clk_sources[src].enable_func(src, 1);
+ if (rc)
+ goto err_enable;
+ }
+ src_votes[src]++;
+
+ return rc;
+
+err_enable:
+ if (soc_clk_sources[src].par != SRC_NONE)
+ local_src_disable_nolock(soc_clk_sources[src].par);
+err_par:
+ return rc;
+}
+
+/* Enable clock source. */
+int local_src_enable(int src)
+{
+ int rc = 0;
+ unsigned long flags;
+
+ if (src == SRC_NONE)
+ return rc;
+
+ spin_lock_irqsave(&src_vote_lock, flags);
+ rc = local_src_enable_nolock(src);
+ spin_unlock_irqrestore(&src_vote_lock, flags);
+
+ return rc;
+}
+
+/* Disable clock source without taking the lock. */
+static int local_src_disable_nolock(int src)
+{
+ int rc = 0;
+
+ if (src_votes[src] > 0)
+ src_votes[src]--;
+ else {
+ pr_warning("%s: Reference counts are incorrect for "
+ "src %d!\n", __func__, src);
+ return rc;
+ }
+
+ if (src_votes[src] == 0) {
+ /* Perform source-specific disable operations. */
+ if (soc_clk_sources[src].enable_func)
+ rc = soc_clk_sources[src].enable_func(src, 0);
+ if (rc)
+ goto err_disable;
+ if (soc_clk_sources[src].par != SRC_NONE)
+ rc = local_src_disable_nolock(soc_clk_sources[src].par);
+ if (rc)
+ goto err_disable_par;
+
+ }
+
+ return rc;
+
+err_disable_par:
+ soc_clk_sources[src].enable_func(src, 1);
+err_disable:
+ src_votes[src]++;
+ return rc;
+}
+
+/* Disable clock source. */
+int local_src_disable(int src)
+{
+ int rc = 0;
+ unsigned long flags;
+
+ if (src == SRC_NONE)
+ return rc;
+
+ spin_lock_irqsave(&src_vote_lock, flags);
+ rc = local_src_disable_nolock(src);
+ spin_unlock_irqrestore(&src_vote_lock, flags);
+
+ return rc;
+}
+
+/*
+ * Clock enable/disable functions
+ */
+
+/* Return non-zero if a clock status registers shows the clock is halted. */
+static int local_clk_is_halted(unsigned id)
+{
+ struct clk_local *clk = &soc_clk_local_tbl[id];
+ int invert = (clk->halt_check == ENABLE);
+ int status_bit = readl(clk->halt_reg) & B(clk->halt_bit);
+ return invert ? !status_bit : status_bit;
+}
+
+/* Perform any register operations required to enable the clock. */
+void local_clk_enable_reg(unsigned id)
+{
+ struct clk_local *clk = &soc_clk_local_tbl[id];
+ void *reg = clk->cc_reg;
+ uint32_t reg_val;
+
+ WARN((clk->type != NORATE) && (clk->current_freq == &local_dummy_freq),
+ "Attempting to enable clock %d before setting its rate. "
+ "Set the rate first!\n", id);
+
+ /* Enable MN counter, if applicable. */
+ reg_val = readl(reg);
+ if (clk->type == MND) {
+ reg_val |= clk->current_freq->mnd_en_mask;
+ writel(reg_val, reg);
+ }
+ /* Enable root. */
+ if (clk->root_en_mask) {
+ reg_val |= clk->root_en_mask;
+ writel(reg_val, reg);
+ }
+ /* Enable branch. */
+ if (clk->br_en_mask) {
+ reg_val |= clk->br_en_mask;
+ writel(reg_val, reg);
+ }
+
+ /* Wait for clock to enable before returning. */
+ if (clk->halt_check == DELAY)
+ udelay(HALT_CHECK_DELAY_US);
+ else if (clk->halt_check == ENABLE || clk->halt_check == HALT
+ || clk->halt_check == ENABLE_VOTED
+ || clk->halt_check == HALT_VOTED) {
+ int count;
+
+ /* Wait up to HALT_CHECK_MAX_LOOPS for clock to enable. */
+ for (count = HALT_CHECK_MAX_LOOPS; local_clk_is_halted(id)
+ && count > 0; count--)
+ udelay(1);
+ if (count == 0)
+ pr_warning("%s: clock %d status stuck at 'off' (bit %d "
+ "of 0x%p).\n", __func__, id, clk->halt_bit,
+ clk->halt_reg);
+ }
+}
+
+/* Perform any register operations required to enable the clock. */
+void local_clk_disable_reg(unsigned id)
+{
+ struct clk_local *clk = &soc_clk_local_tbl[id];
+ void *reg = clk->cc_reg;
+ uint32_t reg_val;
+
+ /* Disable branch. */
+ reg_val = readl(reg);
+ if (clk->br_en_mask) {
+ reg_val &= ~(clk->br_en_mask);
+ writel(reg_val, reg);
+ }
+
+ /* Wait for clock to disable before continuing. */
+ if (clk->halt_check == DELAY || clk->halt_check == ENABLE_VOTED
+ || clk->halt_check == HALT_VOTED)
+ udelay(HALT_CHECK_DELAY_US);
+ else if (clk->halt_check == ENABLE || clk->halt_check == HALT) {
+ int count;
+
+ /* Wait up to HALT_CHECK_MAX_LOOPS for clock to disable. */
+ for (count = HALT_CHECK_MAX_LOOPS; !local_clk_is_halted(id)
+ && count > 0; count--)
+ udelay(1);
+ if (count == 0)
+ pr_warning("%s: clock %d status stuck at 'on' (bit %d "
+ "of 0x%p).\n", __func__, id, clk->halt_bit,
+ clk->halt_reg);
+ }
+
+ /* Disable root. */
+ if (clk->root_en_mask) {
+ reg_val &= ~(clk->root_en_mask);
+ writel(reg_val, reg);
+ }
+ /* Disable MN counter, if applicable. */
+ if (clk->type == MND) {
+ reg_val &= ~(clk->current_freq->mnd_en_mask);
+ writel(reg_val, reg);
+ }
+}
+
+/* Enable a clock with no locking, enabling parent clocks as needed. */
+static int local_clk_enable_nolock(unsigned id)
+{
+ struct clk_local *clk = &soc_clk_local_tbl[id];
+ int rc = 0;
+
+ if (clk->type == RESET)
+ return -EPERM;
+
+ if (!clk->count) {
+ rc = local_vote_sys_vdd(clk->current_freq->sys_vdd);
+ if (rc)
+ goto err_vdd;
+ if (clk->parent != C(NONE)) {
+ rc = local_clk_enable_nolock(clk->parent);
+ if (rc)
+ goto err_par;
+ }
+ rc = local_src_enable(clk->current_freq->src);
+ if (rc)
+ goto err_src;
+ local_clk_enable_reg(id);
+ }
+ clk->count++;
+
+ return rc;
+
+err_src:
+ if (clk->parent != C(NONE))
+ rc = local_clk_disable_nolock(clk->parent);
+err_par:
+ local_unvote_sys_vdd(clk->current_freq->sys_vdd);
+err_vdd:
+ return rc;
+}
+
+/* Disable a clock with no locking, disabling unused parents, too. */
+static int local_clk_disable_nolock(unsigned id)
+{
+ struct clk_local *clk = &soc_clk_local_tbl[id];
+ int rc = 0;
+
+ if (clk->count > 0)
+ clk->count--;
+ else {
+ pr_warning("%s: Reference counts are incorrect for clock %d!\n",
+ __func__, id);
+ return rc;
+ }
+
+ if (clk->count == 0) {
+ local_clk_disable_reg(id);
+ rc = local_src_disable(clk->current_freq->src);
+ if (rc)
+ goto err_src;
+ if (clk->parent != C(NONE))
+ rc = local_clk_disable_nolock(clk->parent);
+ if (rc)
+ goto err_par;
+ rc = local_unvote_sys_vdd(clk->current_freq->sys_vdd);
+ if (rc)
+ goto err_vdd;
+ }
+
+ return rc;
+
+err_vdd:
+ if (clk->parent != C(NONE))
+ rc = local_clk_enable_nolock(clk->parent);
+err_par:
+ local_src_enable(clk->current_freq->src);
+err_src:
+ local_clk_enable_reg(id);
+ clk->count++;
+
+ return rc;
+}
+
+/* Enable a clock and any related power rail. */
+int local_clk_enable(unsigned id)
+{
+ int rc = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&local_clock_reg_lock, flags);
+ rc = local_clk_enable_nolock(id);
+ if (rc)
+ goto unlock;
+ /*
+ * With remote rail control, the remote processor might modify
+ * the clock control register when the rail is enabled/disabled.
+ * Enable the rail inside the lock to protect against this.
+ */
+ rc = soc_set_pwr_rail(id, 1);
+ if (rc)
+ local_clk_disable_nolock(id);
+unlock:
+ spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+
+ return rc;
+}
+
+/* Disable a clock and any related power rail. */
+void local_clk_disable(unsigned id)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&local_clock_reg_lock, flags);
+ soc_set_pwr_rail(id, 0);
+ local_clk_disable_nolock(id);
+ spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+}
+
+/* Turn off a clock at boot, without checking refcounts or disabling parents. */
+void local_clk_auto_off(unsigned id)
+{
+ struct clk_local *clk = &soc_clk_local_tbl[id];
+ unsigned long flags;
+
+ if (clk->type == RESET)
+ return;
+
+ spin_lock_irqsave(&local_clock_reg_lock, flags);
+ local_clk_disable_reg(id);
+ spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+}
+
+/*
+ * Frequency-related functions
+ */
+
+/* Set a clock's frequency. */
+static int _local_clk_set_rate(unsigned id, struct clk_freq_tbl *nf)
+{
+ struct clk_local *clk = &soc_clk_local_tbl[id];
+ struct clk_freq_tbl *cf;
+ const int32_t *chld = clk->children;
+ int i, rc = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&local_clock_reg_lock, flags);
+
+ /* Check if frequency is actually changed. */
+ cf = clk->current_freq;
+ if (nf == cf)
+ goto release_lock;
+
+ /* Disable branch if clock isn't dual-banked with a glitch-free MUX. */
+ if (clk->banked_mnd_masks == NULL) {
+ /* Disable all branches to prevent glitches. */
+ for (i = 0; chld && chld[i] != C(NONE); i++) {
+ struct clk_local *ch = &soc_clk_local_tbl[chld[i]];
+ /* Don't bother turning off if it is already off.
+ * Checking ch->count is cheaper (cache) than reading
+ * and writing to a register (uncached/unbuffered). */
+ if (ch->count)
+ local_clk_disable_reg(chld[i]);
+ }
+ if (clk->count)
+ local_clk_disable_reg(id);
+ }
+
+ if (clk->count) {
+ /* Vote for voltage and source for new freq. */
+ rc = local_vote_sys_vdd(nf->sys_vdd);
+ if (rc)
+ goto sys_vdd_vote_failed;
+ rc = local_src_enable(nf->src);
+ if (rc) {
+ local_unvote_sys_vdd(nf->sys_vdd);
+ goto src_enable_failed;
+ }
+ }
+
+ /* Perform clock-specific frequency switch operations. */
+ BUG_ON(!clk->set_rate);
+ clk->set_rate(clk, nf);
+
+ /* Release requirements of the old freq. */
+ if (clk->count) {
+ local_src_disable(cf->src);
+ local_unvote_sys_vdd(cf->sys_vdd);
+ }
+
+ /* Current freq must be updated before local_clk_enable_reg()
+ * is called to make sure the MNCNTR_EN bit is set correctly. */
+ clk->current_freq = nf;
+
+src_enable_failed:
+sys_vdd_vote_failed:
+ /* Enable any clocks that were disabled. */
+ if (clk->banked_mnd_masks == NULL) {
+ if (clk->count)
+ local_clk_enable_reg(id);
+ /* Enable only branches that were ON before. */
+ for (i = 0; chld && chld[i] != C(NONE); i++) {
+ struct clk_local *ch = &soc_clk_local_tbl[chld[i]];
+ if (ch->count)
+ local_clk_enable_reg(chld[i]);
+ }
+ }
+
+release_lock:
+ spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+ return rc;
+}
+
+/* Set a clock to an exact rate. */
+int local_clk_set_rate(unsigned id, unsigned rate)
+{
+ struct clk_local *clk = &soc_clk_local_tbl[id];
+ struct clk_freq_tbl *nf;
+
+ if (clk->type == NORATE || clk->type == RESET)
+ return -EPERM;
+
+ for (nf = clk->freq_tbl; nf->freq_hz != FREQ_END
+ && nf->freq_hz != rate; nf++)
+ ;
+
+ if (nf->freq_hz == FREQ_END)
+ return -EINVAL;
+
+ return _local_clk_set_rate(id, nf);
+}
+
+/* Set a clock to a rate greater than some minimum. */
+int local_clk_set_min_rate(unsigned id, unsigned rate)
+{
+ struct clk_local *clk = &soc_clk_local_tbl[id];
+ struct clk_freq_tbl *nf;
+
+ if (clk->type == NORATE || clk->type == RESET)
+ return -EPERM;
+
+ for (nf = clk->freq_tbl; nf->freq_hz != FREQ_END
+ && nf->freq_hz < rate; nf++)
+ ;
+
+ if (nf->freq_hz == FREQ_END)
+ return -EINVAL;
+
+ return _local_clk_set_rate(id, nf);
+}
+
+/* Set a clock to a maximum rate. */
+int local_clk_set_max_rate(unsigned id, unsigned rate)
+{
+ return -EPERM;
+}
+
+/* Get the currently-set rate of a clock in Hz. */
+unsigned local_clk_get_rate(unsigned id)
+{
+ struct clk_local *clk = &soc_clk_local_tbl[id];
+ unsigned long flags;
+ unsigned ret = 0;
+
+ if (clk->type == NORATE || clk->type == RESET)
+ return 0;
+
+ spin_lock_irqsave(&local_clock_reg_lock, flags);
+ ret = clk->current_freq->freq_hz;
+ spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+
+ /* Return 0 if the rate has never been set. Might not be correct,
+ * but it's good enough. */
+ if (ret == FREQ_END)
+ ret = 0;
+
+ return ret;
+}
+
+/* Check if a clock is currently enabled. */
+unsigned local_clk_is_enabled(unsigned id)
+{
+ struct clk_local *clk = &soc_clk_local_tbl[id];
+
+ if (clk->type == RESET)
+ return -EPERM;
+
+ return !!(soc_clk_local_tbl[id].count);
+}
+
+/* Return a supported rate that's at least the specified rate. */
+long local_clk_round_rate(unsigned id, unsigned rate)
+{
+ struct clk_local *clk = &soc_clk_local_tbl[id];
+ struct clk_freq_tbl *f;
+
+ if (clk->type == NORATE || clk->type == RESET)
+ return -EINVAL;
+
+ for (f = clk->freq_tbl; f->freq_hz != FREQ_END; f++)
+ if (f->freq_hz >= rate)
+ return f->freq_hz;
+
+ return -EPERM;
+}
diff --git a/arch/arm/mach-msm/clock-local.h b/arch/arm/mach-msm/clock-local.h
new file mode 100644
index 0000000..ebefad5
--- /dev/null
+++ b/arch/arm/mach-msm/clock-local.h
@@ -0,0 +1,232 @@
+/* Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_CLOCK_LOCAL_H
+#define __ARCH_ARM_MACH_MSM_CLOCK_LOCAL_H
+
+#include <linux/spinlock.h>
+#include "clock.h"
+
+/*
+ * Bit manipulation macros
+ */
+#define B(x) BIT(x)
+#define BM(msb, lsb) (((((uint32_t)-1) << (31-msb)) >> (31-msb+lsb)) << lsb)
+#define BVAL(msb, lsb, val) (((val) << lsb) & BM(msb, lsb))
+
+/*
+ * Clock types
+ */
+#define MND 1 /* Integer predivider and fractional MN:D divider. */
+#define BASIC 2 /* Integer divider. */
+#define NORATE 3 /* Just on/off. */
+#define RESET 4 /* Reset only. */
+
+/*
+ * IDs for invalid sources, source selects, and XOs
+ */
+#define SRC_NONE -1
+#define SRC_SEL_NONE -1
+#define XO_NONE -1
+
+/*
+ * Halt/Status Checking Mode Macros
+ */
+#define NOCHECK 0 /* No bit to check, do nothing */
+#define HALT 1 /* Bit pol: 1 = halted */
+#define HALT_VOTED 2 /* Bit pol: 1 = halted; delay on disable */
+#define ENABLE 3 /* Bit pol: 1 = running */
+#define ENABLE_VOTED 4 /* Bit pol: 1 = running; delay on disable */
+#define DELAY 5 /* No bit to check, just delay */
+
+/*
+ * Generic frequency-definition structs and macros
+ */
+struct clk_freq_tbl {
+ const uint32_t freq_hz;
+ const int src;
+ const uint32_t md_val;
+ const uint32_t ns_val;
+ const uint32_t cc_val;
+ uint32_t mnd_en_mask;
+ const unsigned sys_vdd;
+ void *const extra_freq_data;
+};
+
+/* Some clocks have two banks to avoid glitches when switching frequencies.
+ * The unused bank is programmed while running on the other bank, and
+ * switched to afterwards. The following two structs describe the banks. */
+struct bank_mask_info {
+ void *const md_reg;
+ const uint32_t ns_mask;
+ const uint32_t rst_mask;
+ const uint32_t mnd_en_mask;
+ const uint32_t mode_mask;
+};
+
+struct banked_mnd_masks {
+ const uint32_t bank_sel_mask;
+ const struct bank_mask_info bank0_mask;
+ const struct bank_mask_info bank1_mask;
+};
+
+#define F_RAW(f, s, m_v, n_v, c_v, m_m, v, e) { \
+ .freq_hz = f, \
+ .src = s, \
+ .md_val = m_v, \
+ .ns_val = n_v, \
+ .cc_val = c_v, \
+ .mnd_en_mask = m_m, \
+ .sys_vdd = v, \
+ .extra_freq_data = e, \
+ }
+#define FREQ_END (UINT_MAX-1)
+#define F_END F_RAW(FREQ_END, SRC_NONE, 0, 0, 0, 0, LOW, NULL)
+#define PLL_RATE(l, m, n, v, d) { l, m, n, v, (d>>1) }
+
+/*
+ * Generic clock-definition struct and macros
+ */
+struct clk_local {
+ int count;
+ const uint32_t type;
+ void *const ns_reg;
+ void *const cc_reg;
+ void *const md_reg;
+ void *const reset_reg;
+ void *const halt_reg;
+ const uint32_t reset_mask;
+ const uint16_t halt_check;
+ const uint16_t halt_bit;
+ const uint32_t br_en_mask;
+ const uint32_t root_en_mask;
+ const uint32_t ns_mask;
+ const uint32_t cc_mask;
+ const uint32_t test_vector;
+ struct banked_mnd_masks *const banked_mnd_masks;
+ const int parent;
+ const uint32_t *const children;
+ void (*set_rate)(struct clk_local *, struct clk_freq_tbl *);
+ struct clk_freq_tbl *const freq_tbl;
+ struct clk_freq_tbl *current_freq;
+};
+
+#define C(x) L_##x##_CLK
+#define L_NONE_CLK -1
+#define CLK(id, t, ns_r, cc_r, md_r, r_r, r_m, h_r, h_c, h_b, br, root, \
+ n_m, c_m, s_fn, tbl, bmnd, par, chld_lst, tv) \
+ [C(id)] = { \
+ .type = t, \
+ .ns_reg = ns_r, \
+ .cc_reg = cc_r, \
+ .md_reg = md_r, \
+ .reset_reg = r_r, \
+ .halt_reg = h_r, \
+ .halt_check = h_c, \
+ .halt_bit = h_b, \
+ .reset_mask = r_m, \
+ .br_en_mask = br, \
+ .root_en_mask = root, \
+ .ns_mask = n_m, \
+ .cc_mask = c_m, \
+ .test_vector = tv, \
+ .banked_mnd_masks = bmnd, \
+ .parent = C(par), \
+ .children = chld_lst, \
+ .set_rate = s_fn, \
+ .freq_tbl = tbl, \
+ .current_freq = &local_dummy_freq, \
+ }
+
+/*
+ * Convenience macros
+ */
+#define set_1rate(clk) \
+ local_clk_set_rate(C(clk), soc_clk_local_tbl[C(clk)].freq_tbl->freq_hz)
+
+/*
+ * SYS_VDD voltage levels
+ */
+enum sys_vdd_level {
+ NONE,
+ LOW,
+ NOMINAL,
+ HIGH,
+ NUM_SYS_VDD_LEVELS
+};
+
+/*
+ * Clock source descriptions
+ */
+struct clk_source {
+ int (*enable_func)(unsigned src, unsigned enable);
+ const signed par;
+};
+
+/*
+ * Variables from SoC-specific clock drivers
+ */
+extern struct clk_local soc_clk_local_tbl[];
+extern struct clk_source soc_clk_sources[];
+
+/*
+ * Variables from clock-local driver
+ */
+extern spinlock_t local_clock_reg_lock;
+extern struct clk_freq_tbl local_dummy_freq;
+
+/*
+ * Local-clock APIs
+ */
+int local_src_enable(int src);
+int local_src_disable(int src);
+void local_clk_enable_reg(unsigned id);
+void local_clk_disable_reg(unsigned id);
+int local_vote_sys_vdd(enum sys_vdd_level level);
+int local_unvote_sys_vdd(enum sys_vdd_level level);
+
+/*
+ * clk_ops APIs
+ */
+int local_clk_enable(unsigned id);
+void local_clk_disable(unsigned id);
+void local_clk_auto_off(unsigned id);
+int local_clk_set_rate(unsigned id, unsigned rate);
+int local_clk_set_min_rate(unsigned id, unsigned rate);
+int local_clk_set_max_rate(unsigned id, unsigned rate);
+unsigned local_clk_get_rate(unsigned id);
+unsigned local_clk_is_enabled(unsigned id);
+long local_clk_round_rate(unsigned id, unsigned rate);
+
+/*
+ * Required SoC-specific functions, implemented for every supported SoC
+ */
+int soc_update_sys_vdd(enum sys_vdd_level level);
+int soc_set_pwr_rail(unsigned id, int enable);
+int soc_clk_set_flags(unsigned id, unsigned flags);
+int soc_clk_reset(unsigned id, enum clk_reset_action action);
+
+/*
+ * Generic set-rate implementations
+ */
+void set_rate_basic(struct clk_local *clk, struct clk_freq_tbl *nf);
+void set_rate_mnd(struct clk_local *clk, struct clk_freq_tbl *nf);
+void set_rate_nop(struct clk_local *clk, struct clk_freq_tbl *nf);
+
+#endif /* __ARCH_ARM_MACH_MSM_CLOCK_LOCAL_H */