summaryrefslogtreecommitdiff
path: root/include/soc
diff options
context:
space:
mode:
authorTaniya Das <tdas@codeaurora.org>2016-01-07 18:14:25 +0530
committerRohit Vaswani <rvaswani@codeaurora.org>2016-03-01 13:00:24 -0800
commit1ec7358a6161bdfe0482e4bd0d2b4448eea54449 (patch)
tree13fabf9d4d7b06870ef3f0ac0031d04733b5967e /include/soc
parentedf938dde9457d3c45a70ed3228c4c4ff61f1e11 (diff)
clk: msm: Add support for MSM clocks
Support added for MSM clock and modifications in the clk framework to use the MSM clock framework. Change-Id: Ibbcf0ffbf9d30dde2dcb0e943225ad95dd4e857d Signed-off-by: Taniya Das <tdas@codeaurora.org>
Diffstat (limited to 'include/soc')
-rw-r--r--include/soc/qcom/clock-alpha-pll.h94
-rw-r--r--include/soc/qcom/clock-local2.h256
-rw-r--r--include/soc/qcom/clock-pll.h231
-rw-r--r--include/soc/qcom/clock-rpm.h180
-rw-r--r--include/soc/qcom/clock-voter.h51
-rw-r--r--include/soc/qcom/msm-clock-controller.h144
6 files changed, 956 insertions, 0 deletions
diff --git a/include/soc/qcom/clock-alpha-pll.h b/include/soc/qcom/clock-alpha-pll.h
new file mode 100644
index 000000000000..b5a34b4cecb5
--- /dev/null
+++ b/include/soc/qcom/clock-alpha-pll.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2012-2015, The Linux Foundation. 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.
+ *
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_CLOCK_ALPHA_PLL_H
+#define __ARCH_ARM_MACH_MSM_CLOCK_ALPHA_PLL_H
+
+#include <linux/spinlock.h>
+#include <linux/clk/msm-clk-provider.h>
+
+struct alpha_pll_masks {
+ u32 lock_mask; /* lock_det bit */
+ u32 active_mask; /* active_flag in FSM mode */
+ u32 update_mask; /* update bit for dynamic update */
+ u32 vco_mask; /* vco_sel bits */
+ u32 vco_shift;
+ u32 alpha_en_mask; /* alpha_en bit */
+ u32 output_mask; /* pllout_* bits */
+ u32 post_div_mask;
+
+ u32 test_ctl_lo_mask;
+ u32 test_ctl_hi_mask;
+};
+
+struct alpha_pll_vco_tbl {
+ u32 vco_val;
+ unsigned long min_freq;
+ unsigned long max_freq;
+};
+
+#define VCO(a, b, c) { \
+ .vco_val = a,\
+ .min_freq = b,\
+ .max_freq = c,\
+}
+
+struct alpha_pll_clk {
+ struct alpha_pll_masks *masks;
+ void *const __iomem *base;
+ u32 offset;
+
+ /* if fsm_en_mask is set, config PLL to FSM mode */
+ u32 fsm_reg_offset;
+ u32 fsm_en_mask;
+
+ u32 enable_config; /* bitmask of outputs to be enabled */
+ u32 post_div_config; /* masked post divider setting */
+ u32 config_ctl_val; /* config register init value */
+ u32 test_ctl_lo_val; /* test control settings */
+ u32 test_ctl_hi_val;
+
+ struct alpha_pll_vco_tbl *vco_tbl;
+ u32 num_vco;
+ u32 current_vco_val;
+ bool inited;
+ bool slew;
+ bool no_prepared_reconfig;
+
+ /*
+ * Some chipsets need the offline request bit to be
+ * cleared on a second write to the register, even though
+ * SW wants the bit to be set. Set this flag to indicate
+ * that the workaround is required.
+ */
+ bool offline_bit_workaround;
+ bool is_fabia;
+ unsigned long min_supported_freq;
+ struct clk c;
+};
+
+static inline struct alpha_pll_clk *to_alpha_pll_clk(struct clk *c)
+{
+ return container_of(c, struct alpha_pll_clk, c);
+}
+
+
+#endif
+extern void __init_alpha_pll(struct clk *c);
+extern struct clk_ops clk_ops_alpha_pll;
+extern struct clk_ops clk_ops_alpha_pll_hwfsm;
+extern struct clk_ops clk_ops_fixed_alpha_pll;
+extern struct clk_ops clk_ops_dyna_alpha_pll;
+extern struct clk_ops clk_ops_fixed_fabia_alpha_pll;
+extern struct clk_ops clk_ops_fabia_alpha_pll;
diff --git a/include/soc/qcom/clock-local2.h b/include/soc/qcom/clock-local2.h
new file mode 100644
index 000000000000..42c991194391
--- /dev/null
+++ b/include/soc/qcom/clock-local2.h
@@ -0,0 +1,256 @@
+/* Copyright (c) 2012-2015, The Linux Foundation. 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.
+ *
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_CLOCK_LOCAL_2_H
+#define __ARCH_ARM_MACH_MSM_CLOCK_LOCAL_2_H
+
+#include <linux/spinlock.h>
+#include <linux/clk/msm-clk-provider.h>
+#include <linux/clk/msm-clk.h>
+
+/*
+ * Generic frequency-definition structs and macros
+ */
+
+/**
+ * @freq_hz: output rate
+ * @src_freq: source freq for dynamic pll. For fixed plls, set to 0.
+ * @src_clk: source clock for freq_hz
+ * @m_val: M value corresponding to freq_hz
+ * @n_val: N value corresponding to freq_hz
+ * @d_val: D value corresponding to freq_hz
+ * @div_src_val: Pre divider value and source selection mux index for freq_hz
+ * @sys_vdd: Voltage level required for freq_hz
+ */
+struct clk_freq_tbl {
+ unsigned long freq_hz;
+ unsigned long src_freq;
+ struct clk *src_clk;
+ u32 m_val;
+ u32 n_val;
+ u32 d_val;
+ u32 div_src_val;
+ const unsigned sys_vdd;
+};
+
+#define FREQ_END (ULONG_MAX-1)
+#define F_END { .freq_hz = FREQ_END }
+#define FIXED_CLK_SRC 0
+/*
+ * Generic clock-definition struct and macros
+ */
+/**
+ * struct rcg_clk - root clock generator
+ * @cmd_rcgr_reg: command register
+ * @set_rate: function to set frequency
+ * @freq_tbl: frequency table for this RCG
+ * @current_freq: current RCG frequency
+ * @c: generic clock data
+ * @non_local_children: set if RCG has at least one branch owned by a diff EE
+ * @force_enable_rcgr: set if RCG needs to be force enabled/disabled during
+ * power sequence
+ * @base: pointer to base address of ioremapped registers.
+ */
+struct rcg_clk {
+ u32 cmd_rcgr_reg;
+
+ void (*set_rate)(struct rcg_clk *, struct clk_freq_tbl *);
+
+ struct clk_freq_tbl *freq_tbl;
+ struct clk_freq_tbl *current_freq;
+ struct clk c;
+
+ bool non_local_children;
+ bool force_enable_rcgr;
+ void *const __iomem *base;
+};
+
+static inline struct rcg_clk *to_rcg_clk(struct clk *clk)
+{
+ return container_of(clk, struct rcg_clk, c);
+}
+
+extern struct clk_freq_tbl rcg_dummy_freq;
+
+/**
+ * struct branch_clk - branch clock
+ * @set_rate: Set the frequency of this branch clock.
+ * @c: clk
+ * @cbcr_reg: branch control register
+ * @bcr_reg: block reset register
+ * @has_sibling: true if other branches are derived from this branch's source
+ * @cur_div: current branch divider value
+ * @max_div: maximum branch divider value (if zero, no divider exists)
+ * @halt_check: halt checking type
+ * @toggle_memory: toggle memory during enable/disable if true
+ * @no_halt_check_on_disable: When set, do not check status bit during
+ * clk_disable().
+ * @check_enable_bit: Check the enable bit to determine clock status
+ during handoff.
+ * @base: pointer to base address of ioremapped registers.
+ */
+struct branch_clk {
+ void (*set_rate)(struct branch_clk *, struct clk_freq_tbl *);
+ struct clk c;
+ u32 cbcr_reg;
+ u32 bcr_reg;
+ int has_sibling;
+ u32 cur_div;
+ u32 max_div;
+ const u32 halt_check;
+ bool toggle_memory;
+ bool no_halt_check_on_disable;
+ bool check_enable_bit;
+ void *const __iomem *base;
+};
+
+static inline struct branch_clk *to_branch_clk(struct clk *clk)
+{
+ return container_of(clk, struct branch_clk, c);
+}
+
+/**
+ * struct local_vote_clk - Voteable branch clock
+ * @c: clk
+ * @cbcr_reg: branch control register
+ * @vote_reg: voting register
+ * @en_mask: enable mask
+ * @halt_check: halt checking type
+ * @base: pointer to base address of ioremapped registers.
+ * An on/off switch with a rate derived from the parent.
+ */
+struct local_vote_clk {
+ struct clk c;
+ u32 cbcr_reg;
+ u32 vote_reg;
+ u32 bcr_reg;
+ u32 en_mask;
+ const u32 halt_check;
+ void * __iomem *base;
+};
+
+static inline struct local_vote_clk *to_local_vote_clk(struct clk *clk)
+{
+ return container_of(clk, struct local_vote_clk, c);
+}
+
+/**
+ * struct reset_clk - Reset clock
+ * @c: clk
+ * @reset_reg: block reset register
+ * @base: pointer to base address of ioremapped registers.
+ */
+struct reset_clk {
+ struct clk c;
+ u32 reset_reg;
+ void *__iomem *base;
+};
+
+static inline struct reset_clk *to_reset_clk(struct clk *clk)
+{
+ return container_of(clk, struct reset_clk, c);
+}
+/**
+ * struct measure_clk - for rate measurement debug use
+ * @sample_ticks: sample period in reference clock ticks
+ * @multiplier: measurement scale-up factor
+ * @divider: measurement scale-down factor
+ * @c: clk
+*/
+struct measure_clk {
+ u64 sample_ticks;
+ u32 multiplier;
+ u32 divider;
+
+ struct clk c;
+};
+
+struct measure_clk_data {
+ struct clk *cxo;
+ u32 plltest_reg;
+ u32 plltest_val;
+ u32 xo_div4_cbcr;
+ u32 ctl_reg;
+ u32 status_reg;
+ void *const __iomem *base;
+};
+
+static inline struct measure_clk *to_measure_clk(struct clk *clk)
+{
+ return container_of(clk, struct measure_clk, c);
+}
+
+/**
+ * struct gate_clk
+ * @c: clk
+ * @en_mask: ORed with @en_reg to enable gate clk
+ * @en_reg: register used to enable/disable gate clk
+ * @base: pointer to base address of ioremapped registers
+ */
+struct gate_clk {
+ struct clk c;
+ u32 en_mask;
+ u32 en_reg;
+ unsigned int delay_us;
+ void *const __iomem *base;
+};
+
+static inline struct gate_clk *to_gate_clk(struct clk *clk)
+{
+ return container_of(clk, struct gate_clk, c);
+}
+
+/*
+ * Generic set-rate implementations
+ */
+void set_rate_mnd(struct rcg_clk *clk, struct clk_freq_tbl *nf);
+void set_rate_hid(struct rcg_clk *clk, struct clk_freq_tbl *nf);
+
+/*
+ * Variables from the clock-local driver
+ */
+extern spinlock_t local_clock_reg_lock;
+
+extern struct clk_ops clk_ops_empty;
+extern struct clk_ops clk_ops_rcg;
+extern struct clk_ops clk_ops_rcg_mnd;
+extern struct clk_ops clk_ops_branch;
+extern struct clk_ops clk_ops_vote;
+extern struct clk_ops clk_ops_rcg_hdmi;
+extern struct clk_ops clk_ops_rcg_edp;
+extern struct clk_ops clk_ops_byte;
+extern struct clk_ops clk_ops_pixel;
+extern struct clk_ops clk_ops_byte_multiparent;
+extern struct clk_ops clk_ops_pixel_multiparent;
+extern struct clk_ops clk_ops_edppixel;
+extern struct clk_ops clk_ops_gate;
+extern struct clk_ops clk_ops_rst;
+extern struct clk_mux_ops mux_reg_ops;
+extern struct mux_div_ops rcg_mux_div_ops;
+extern struct clk_div_ops postdiv_reg_ops;
+
+enum handoff pixel_rcg_handoff(struct clk *clk);
+enum handoff byte_rcg_handoff(struct clk *clk);
+unsigned long measure_get_rate(struct clk *c);
+
+/*
+ * Clock definition macros
+ */
+#define DEFINE_CLK_MEASURE(name) \
+ struct clk name = { \
+ .ops = &clk_ops_empty, \
+ .dbg_name = #name, \
+ CLK_INIT(name), \
+ }; \
+
+#endif /* __ARCH_ARM_MACH_MSM_CLOCK_LOCAL_2_H */
diff --git a/include/soc/qcom/clock-pll.h b/include/soc/qcom/clock-pll.h
new file mode 100644
index 000000000000..c17376966a09
--- /dev/null
+++ b/include/soc/qcom/clock-pll.h
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2012-2015, The Linux Foundation. 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.
+ *
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_CLOCK_PLL_H
+#define __ARCH_ARM_MACH_MSM_CLOCK_PLL_H
+
+#include <linux/clk/msm-clk-provider.h>
+
+/**
+ * struct pll_freq_tbl - generic PLL frequency definition
+ * @freq_hz: pll frequency in hz
+ * @l_val: pll l value
+ * @m_val: pll m value
+ * @n_val: pll n value
+ * @post_div_val: pll post divider value
+ * @pre_div_val: pll pre-divider value
+ * @vco_val: pll vco value
+ */
+struct pll_freq_tbl {
+ const u32 freq_hz;
+ const u32 l_val;
+ const u32 m_val;
+ const u32 n_val;
+ const u32 post_div_val;
+ const u32 pre_div_val;
+ const u32 vco_val;
+};
+
+/**
+ * struct pll_config_masks - PLL config masks struct
+ * @post_div_mask: mask for post divider bits location
+ * @pre_div_mask: mask for pre-divider bits location
+ * @vco_mask: mask for vco bits location
+ * @mn_en_mask: ORed with pll config register to enable the mn counter
+ * @main_output_mask: ORed with pll config register to enable the main output
+ * @apc_pdn_mask: ORed with pll config register to enable/disable APC PDN
+ * @lock_mask: Mask that indicates that the PLL has locked
+ */
+struct pll_config_masks {
+ u32 apc_pdn_mask;
+ u32 post_div_mask;
+ u32 pre_div_mask;
+ u32 vco_mask;
+ u32 mn_en_mask;
+ u32 main_output_mask;
+ u32 early_output_mask;
+ u32 lock_mask;
+};
+
+struct pll_config_vals {
+ u32 post_div_masked;
+ u32 pre_div_masked;
+ u32 config_ctl_val;
+ u32 config_ctl_hi_val;
+ u32 test_ctl_lo_val;
+ u32 test_ctl_hi_val;
+ u32 alpha_val;
+ bool enable_mn;
+};
+
+struct pll_spm_ctrl {
+ u32 offset;
+ u32 event_bit;
+ void __iomem *spm_base;
+};
+
+#define PLL_FREQ_END (UINT_MAX-1)
+#define PLL_F_END { .freq_hz = PLL_FREQ_END }
+
+/**
+ * struct pll_vote_clk - phase locked loop (HW voteable)
+ * @soft_vote: soft voting variable for multiple PLL software instances
+ * @soft_vote_mask: soft voting mask for multiple PLL software instances
+ * @en_reg: enable register
+ * @en_mask: ORed with @en_reg to enable the clock
+ * @status_mask: ANDed with @status_reg to determine if PLL is active.
+ * @status_reg: status register
+ * @c: clock
+ */
+struct pll_vote_clk {
+ u32 *soft_vote;
+ u32 soft_vote_mask;
+ void __iomem *const en_reg;
+ u32 en_mask;
+ void __iomem *const status_reg;
+ u32 status_mask;
+
+ struct clk c;
+ void *const __iomem *base;
+};
+
+extern struct clk_ops clk_ops_pll_vote;
+extern struct clk_ops clk_ops_pll_acpu_vote;
+extern struct clk_ops clk_ops_pll_sleep_vote;
+
+/* Soft voting values */
+#define PLL_SOFT_VOTE_PRIMARY BIT(0)
+#define PLL_SOFT_VOTE_ACPU BIT(1)
+#define PLL_SOFT_VOTE_AUX BIT(2)
+
+static inline struct pll_vote_clk *to_pll_vote_clk(struct clk *c)
+{
+ return container_of(c, struct pll_vote_clk, c);
+}
+
+/**
+ * struct pll_clk - phase locked loop
+ * @mode_reg: enable register
+ * @l_reg: l value register
+ * @m_reg: m value register
+ * @n_reg: n value register
+ * @config_reg: configuration register, contains mn divider enable, pre divider,
+ * post divider and vco configuration. register name can be configure register
+ * or user_ctl register depending on targets
+ * @config_ctl_reg: "expert" configuration register
+ * @config_ctl_hi_reg: upper 32 bits of the "expert" configuration register
+ * @status_reg: status register, contains the lock detection bit
+ * @init_test_ctl: initialize the test control register
+ * @pgm_test_ctl_enable: program the test_ctl register in the enable sequence
+ * @test_ctl_dbg: if false will configure the test control registers.
+ * @masks: masks used for settings in config_reg
+ * @vals: configuration values to be written to PLL registers
+ * @freq_tbl: pll freq table
+ * @no_prepared_reconfig: Fail round_rate if pll is prepared
+ * @c: clk
+ * @base: pointer to base address of ioremapped registers.
+ */
+struct pll_clk {
+ void __iomem *const mode_reg;
+ void __iomem *const l_reg;
+ void __iomem *const m_reg;
+ void __iomem *const n_reg;
+ void __iomem *const alpha_reg;
+ void __iomem *const config_reg;
+ void __iomem *const config_ctl_reg;
+ void __iomem *const config_ctl_hi_reg;
+ void __iomem *const status_reg;
+ void __iomem *const alt_status_reg;
+ void __iomem *const test_ctl_lo_reg;
+ void __iomem *const test_ctl_hi_reg;
+
+ bool init_test_ctl;
+ bool pgm_test_ctl_enable;
+ bool test_ctl_dbg;
+
+ struct pll_config_masks masks;
+ struct pll_config_vals vals;
+ struct pll_freq_tbl *freq_tbl;
+
+ unsigned long src_rate;
+ unsigned long min_rate;
+ unsigned long max_rate;
+
+ bool inited;
+ bool no_prepared_reconfig;
+
+ struct pll_spm_ctrl spm_ctrl;
+ struct clk c;
+ void *const __iomem *base;
+};
+
+extern struct clk_ops clk_ops_local_pll;
+extern struct clk_ops clk_ops_sr2_pll;
+extern struct clk_ops clk_ops_variable_rate_pll;
+extern struct clk_ops clk_ops_variable_rate_pll_hwfsm;
+
+void __variable_rate_pll_init(struct clk *c);
+
+static inline struct pll_clk *to_pll_clk(struct clk *c)
+{
+ return container_of(c, struct pll_clk, c);
+}
+
+int sr_pll_clk_enable(struct clk *c);
+int sr_hpm_lp_pll_clk_enable(struct clk *c);
+
+struct pll_alt_config {
+ u32 val;
+ u32 mask;
+};
+
+struct pll_config {
+ u32 l;
+ u32 m;
+ u32 n;
+ u32 vco_val;
+ u32 vco_mask;
+ u32 pre_div_val;
+ u32 pre_div_mask;
+ u32 post_div_val;
+ u32 post_div_mask;
+ u32 mn_ena_val;
+ u32 mn_ena_mask;
+ u32 main_output_val;
+ u32 main_output_mask;
+ u32 aux_output_val;
+ u32 aux_output_mask;
+ u32 cfg_ctl_val;
+ /* SR2 PLL specific fields */
+ u32 add_factor_val;
+ u32 add_factor_mask;
+ struct pll_alt_config alt_cfg;
+};
+
+struct pll_config_regs {
+ void __iomem *l_reg;
+ void __iomem *m_reg;
+ void __iomem *n_reg;
+ void __iomem *config_reg;
+ void __iomem *config_alt_reg;
+ void __iomem *config_ctl_reg;
+ void __iomem *mode_reg;
+ void *const __iomem *base;
+};
+
+void configure_sr_pll(struct pll_config *config, struct pll_config_regs *regs,
+ u32 ena_fsm_mode);
+void configure_sr_hpm_lp_pll(struct pll_config *config,
+ struct pll_config_regs *, u32 ena_fsm_mode);
+#endif
diff --git a/include/soc/qcom/clock-rpm.h b/include/soc/qcom/clock-rpm.h
new file mode 100644
index 000000000000..18fedd4c97f7
--- /dev/null
+++ b/include/soc/qcom/clock-rpm.h
@@ -0,0 +1,180 @@
+/* Copyright (c) 2010-2015, The Linux Foundation. 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.
+ *
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_CLOCK_RPM_H
+#define __ARCH_ARM_MACH_MSM_CLOCK_RPM_H
+
+#include <linux/clk/msm-clk-provider.h>
+#include <soc/qcom/rpm-smd.h>
+
+#define RPM_SMD_KEY_RATE 0x007A484B
+#define RPM_SMD_KEY_ENABLE 0x62616E45
+#define RPM_SMD_KEY_STATE 0x54415453
+
+#define RPM_CLK_BUFFER_A_REQ 0x616B6C63
+#define RPM_KEY_SOFTWARE_ENABLE 0x6E657773
+#define RPM_KEY_PIN_CTRL_CLK_BUFFER_ENABLE_KEY 0x62636370
+
+struct clk_ops;
+struct clk_rpmrs_data;
+extern struct clk_ops clk_ops_rpm;
+extern struct clk_ops clk_ops_rpm_branch;
+
+struct rpm_clk {
+ int rpm_res_type;
+ int rpm_key;
+ int rpm_clk_id;
+ const int rpm_status_id;
+ bool active_only;
+ bool enabled;
+ bool branch; /* true: RPM only accepts 1 for ON and 0 for OFF */
+ struct clk_rpmrs_data *rpmrs_data;
+ struct rpm_clk *peer;
+ struct clk c;
+ uint32_t *last_active_set_vote;
+ uint32_t *last_sleep_set_vote;
+};
+
+static inline struct rpm_clk *to_rpm_clk(struct clk *clk)
+{
+ return container_of(clk, struct rpm_clk, c);
+}
+
+/*
+ * RPM scaling enable function used for target that has an RPM resource for
+ * rpm clock scaling enable.
+ */
+int enable_rpm_scaling(void);
+
+int vote_bimc(struct rpm_clk *r, uint32_t value);
+
+extern struct clk_rpmrs_data clk_rpmrs_data_smd;
+
+/*
+ * A note on name##last_{active,sleep}_set_vote below:
+ * We track the last active and sleep set votes across both
+ * active-only and active+sleep set clocks. We use the same
+ * tracking variables for both clocks in order to keep both
+ * updated about the last vote irrespective of which clock
+ * actually made the request. This is the only way to allow
+ * optimizations that prevent duplicate requests from being sent
+ * to the RPM. Separate tracking does not work since it is not
+ * possible to know if the peer's last request was actually sent
+ * to the RPM.
+ */
+
+#define __DEFINE_CLK_RPM(name, active, type, r_id, stat_id, dep, key, \
+ rpmrsdata) \
+ static struct rpm_clk active; \
+ static uint32_t name##last_active_set_vote; \
+ static uint32_t name##last_sleep_set_vote; \
+ static struct rpm_clk name = { \
+ .rpm_res_type = (type), \
+ .rpm_clk_id = (r_id), \
+ .rpm_status_id = (stat_id), \
+ .rpm_key = (key), \
+ .peer = &active, \
+ .rpmrs_data = (rpmrsdata),\
+ .last_active_set_vote = &name##last_active_set_vote, \
+ .last_sleep_set_vote = &name##last_sleep_set_vote, \
+ .c = { \
+ .ops = &clk_ops_rpm, \
+ .dbg_name = #name, \
+ CLK_INIT(name.c), \
+ .depends = dep, \
+ }, \
+ }; \
+ static struct rpm_clk active = { \
+ .rpm_res_type = (type), \
+ .rpm_clk_id = (r_id), \
+ .rpm_status_id = (stat_id), \
+ .rpm_key = (key), \
+ .peer = &name, \
+ .active_only = true, \
+ .rpmrs_data = (rpmrsdata),\
+ .last_active_set_vote = &name##last_active_set_vote, \
+ .last_sleep_set_vote = &name##last_sleep_set_vote, \
+ .c = { \
+ .ops = &clk_ops_rpm, \
+ .dbg_name = #active, \
+ CLK_INIT(active.c), \
+ .depends = dep, \
+ }, \
+ };
+
+#define __DEFINE_CLK_RPM_BRANCH(name, active, type, r_id, stat_id, r, \
+ key, rpmrsdata) \
+ static struct rpm_clk active; \
+ static uint32_t name##last_active_set_vote; \
+ static uint32_t name##last_sleep_set_vote; \
+ static struct rpm_clk name = { \
+ .rpm_res_type = (type), \
+ .rpm_clk_id = (r_id), \
+ .rpm_status_id = (stat_id), \
+ .rpm_key = (key), \
+ .peer = &active, \
+ .branch = true, \
+ .rpmrs_data = (rpmrsdata),\
+ .last_active_set_vote = &name##last_active_set_vote, \
+ .last_sleep_set_vote = &name##last_sleep_set_vote, \
+ .c = { \
+ .ops = &clk_ops_rpm_branch, \
+ .dbg_name = #name, \
+ .rate = (r), \
+ CLK_INIT(name.c), \
+ }, \
+ }; \
+ static struct rpm_clk active = { \
+ .rpm_res_type = (type), \
+ .rpm_clk_id = (r_id), \
+ .rpm_status_id = (stat_id), \
+ .rpm_key = (key), \
+ .peer = &name, \
+ .active_only = true, \
+ .branch = true, \
+ .rpmrs_data = (rpmrsdata),\
+ .last_active_set_vote = &name##last_active_set_vote, \
+ .last_sleep_set_vote = &name##last_sleep_set_vote, \
+ .c = { \
+ .ops = &clk_ops_rpm_branch, \
+ .dbg_name = #active, \
+ .rate = (r), \
+ CLK_INIT(active.c), \
+ }, \
+ };
+
+#define DEFINE_CLK_RPM_SMD(name, active, type, r_id, dep) \
+ __DEFINE_CLK_RPM(name, active, type, r_id, 0, dep, \
+ RPM_SMD_KEY_RATE, &clk_rpmrs_data_smd)
+
+#define DEFINE_CLK_RPM_SMD_BRANCH(name, active, type, r_id, r) \
+ __DEFINE_CLK_RPM_BRANCH(name, active, type, r_id, 0, r, \
+ RPM_SMD_KEY_ENABLE, &clk_rpmrs_data_smd)
+
+#define DEFINE_CLK_RPM_SMD_QDSS(name, active, type, r_id) \
+ __DEFINE_CLK_RPM(name, active, type, r_id, \
+ 0, 0, RPM_SMD_KEY_STATE, &clk_rpmrs_data_smd)
+/*
+ * The RPM XO buffer clock management code aggregates votes for pin-control mode
+ * and software mode separately. Software-enable has higher priority over pin-
+ * control, and if the software-mode aggregation results in a 'disable', the
+ * buffer will be left in pin-control mode if a pin-control vote is in place.
+ */
+#define DEFINE_CLK_RPM_SMD_XO_BUFFER(name, active, r_id) \
+ __DEFINE_CLK_RPM_BRANCH(name, active, RPM_CLK_BUFFER_A_REQ, r_id, 0, \
+ 1000, RPM_KEY_SOFTWARE_ENABLE, &clk_rpmrs_data_smd)
+
+#define DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(name, active, r_id) \
+ __DEFINE_CLK_RPM_BRANCH(name, active, RPM_CLK_BUFFER_A_REQ, r_id, 0, \
+ 1000, RPM_KEY_PIN_CTRL_CLK_BUFFER_ENABLE_KEY, &clk_rpmrs_data_smd)
+#endif
diff --git a/include/soc/qcom/clock-voter.h b/include/soc/qcom/clock-voter.h
new file mode 100644
index 000000000000..9eb3898db1e8
--- /dev/null
+++ b/include/soc/qcom/clock-voter.h
@@ -0,0 +1,51 @@
+/* Copyright (c) 2010-2013, The Linux Foundation. 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.
+ *
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_CLOCK_VOTER_H
+#define __ARCH_ARM_MACH_MSM_CLOCK_VOTER_H
+
+#include <linux/clk/msm-clk-provider.h>
+
+struct clk_ops;
+extern struct clk_ops clk_ops_voter;
+
+struct clk_voter {
+ int is_branch;
+ bool enabled;
+ struct clk c;
+};
+
+static inline struct clk_voter *to_clk_voter(struct clk *clk)
+{
+ return container_of(clk, struct clk_voter, c);
+}
+
+#define __DEFINE_CLK_VOTER(clk_name, _parent, _default_rate, _is_branch) \
+ struct clk_voter clk_name = { \
+ .is_branch = (_is_branch), \
+ .c = { \
+ .parent = _parent, \
+ .dbg_name = #clk_name, \
+ .ops = &clk_ops_voter, \
+ .rate = _default_rate, \
+ CLK_INIT(clk_name.c), \
+ }, \
+ }
+
+#define DEFINE_CLK_VOTER(clk_name, _parent, _default_rate) \
+ __DEFINE_CLK_VOTER(clk_name, _parent, _default_rate, 0)
+
+#define DEFINE_CLK_BRANCH_VOTER(clk_name, _parent) \
+ __DEFINE_CLK_VOTER(clk_name, _parent, 1000, 1)
+
+#endif
diff --git a/include/soc/qcom/msm-clock-controller.h b/include/soc/qcom/msm-clock-controller.h
new file mode 100644
index 000000000000..d6bd4e03af0d
--- /dev/null
+++ b/include/soc/qcom/msm-clock-controller.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. 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.
+ *
+ */
+
+#ifndef __ARCH_ARM_MSM_CLOCK_CONTROLLER_H
+#define __ARCH_ARM_MSM_CLOCK_CONTROLLER_H
+
+#include <linux/list.h>
+#include <linux/clkdev.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#define dt_err(np, fmt, ...) \
+ pr_err("%s: " fmt, np->name, ##__VA_ARGS__)
+#define dt_prop_err(np, str, fmt, ...) \
+ dt_err(np, "%s: " fmt, str, ##__VA_ARGS__)
+
+/**
+ * struct msmclk_parser
+ * @compatible
+ * matches compatible property from devicetree
+ * @parsedt
+ * constructs & returns an instance of the appropriate obj based on
+ * the data from devicetree.
+ */
+struct msmclk_parser {
+ struct list_head list;
+ char *compatible;
+ void * (*parsedt)(struct device *dev, struct device_node *of);
+};
+
+#define MSMCLK_PARSER(fn, str, id) \
+static struct msmclk_parser _msmclk_##fn##id = { \
+ .list = LIST_HEAD_INIT(_msmclk_##fn##id.list), \
+ .compatible = str, \
+ .parsedt = fn, \
+}; \
+static int __init _msmclk_init_##fn##id(void) \
+{ \
+ msmclk_parser_register(&_msmclk_##fn##id); \
+ return 0; \
+} \
+early_initcall(_msmclk_init_##fn##id)
+
+/*
+ * struct msmclk_data
+ * @base
+ * ioremapped region for sub_devices
+ * @list
+ * tracks all registered driver instances
+ * @htable
+ * tracks all registered child clocks
+ * @clk_tbl
+ * array of clk_lookup to be registered with the clock framework
+ */
+#define HASHTABLE_SIZE 200
+struct msmclk_data {
+ void __iomem *base;
+ struct device *dev;
+ struct list_head list;
+ struct hlist_head htable[HASHTABLE_SIZE];
+ struct clk_lookup *clk_tbl;
+ int clk_tbl_size;
+ int max_clk_tbl_size;
+};
+
+#if defined(CONFIG_MSM_CLK_CONTROLLER_V2)
+
+/* Utility functions */
+int of_property_count_phandles(struct device_node *np, char *propname);
+int of_property_read_phandle_index(struct device_node *np, char *propname,
+ int index, phandle *p);
+void *msmclk_generic_clk_init(struct device *dev, struct device_node *np,
+ struct clk *c);
+
+/*
+ * msmclk_parser_register
+ * Registers a parser which will be matched with a node from dt
+ * according to the compatible string.
+ */
+void msmclk_parser_register(struct msmclk_parser *);
+
+/*
+ * msmclk_parse_phandle
+ * On hashtable miss, the corresponding entry will be retrieved from
+ * devicetree, and added to the hashtable.
+ */
+void *msmclk_parse_phandle(struct device *dev, phandle key);
+/*
+ * msmclk_lookup_phandle
+ * Straightforward hashtable lookup
+ */
+void *msmclk_lookup_phandle(struct device *dev, phandle key);
+
+int __init msmclk_init(void);
+#else
+
+static inline int of_property_count_phandles(struct device_node *np,
+ char *propname)
+{
+ return 0;
+}
+
+static inline int of_property_read_phandle_index(struct device_node *np,
+ char *propname, int index, phandle *p)
+{
+ return 0;
+}
+
+static inline void *msmclk_generic_clk_init(struct device *dev,
+ struct device_node *np, struct clk *c)
+{
+ return ERR_PTR(-EINVAL);
+}
+
+static inline void msmclk_parser_register(struct msmclk_parser *p) {};
+
+static inline void *msmclk_parse_phandle(struct device *dev, phandle key)
+{
+ return ERR_PTR(-EINVAL);
+}
+
+static inline void *msmclk_lookup_phandle(struct device *dev, phandle key)
+{
+ return ERR_PTR(-EINVAL);
+}
+
+static inline int __init msmclk_init(void)
+{
+ return 0;
+}
+
+#endif /* CONFIG_MSM_CLK_CONTROLLER_V2 */
+#endif /* __ARCH_ARM_MSM_CLOCK_CONTROLLER_H */