msm: acpuclock: Implement acpuclock APIs through function pointers

Create a generic wrapper acpuclock driver in acpuclock.c to call
SoC-specific function pointer API implementations.  With the
exception of iomap conflicts, this should allow multiple acpuclock
driver implementations to be compiled into the same kernel binary.

Signed-off-by: Matt Wagantall <mattw@codeaurora.org>

Conflicts:

	arch/arm/mach-msm/acpuclock-7201.c
	arch/arm/mach-msm/board-msm8960.c
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index a23b564..6c40fdc 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -17,6 +17,7 @@
 	endif
 endif
 
+obj-y += acpuclock.o
 obj-$(CONFIG_ARCH_MSM_ARM11) += acpuclock-7201.o
 obj-$(CONFIG_ARCH_MSM_SCORPION) += pmu.o
 obj-$(CONFIG_ARCH_MSM_CORTEX_A5) += acpuclock-7201.o
diff --git a/arch/arm/mach-msm/acpuclock-7201.c b/arch/arm/mach-msm/acpuclock-7201.c
index 9422cda..f06b069 100644
--- a/arch/arm/mach-msm/acpuclock-7201.c
+++ b/arch/arm/mach-msm/acpuclock-7201.c
@@ -46,6 +46,8 @@
 #define PLL4_MODE	(MSM_CLK_CTL_BASE + 0x374)
 #define PLL4_L_VAL	(MSM_CLK_CTL_BASE + 0x378)
 
+#define POWER_COLLAPSE_KHZ 19200
+
 /* Max CPU frequency allowed by hardware while in standby waiting for an irq. */
 #define MAX_WAIT_FOR_IRQ_KHZ 128000
 
@@ -77,7 +79,6 @@
 	uint32_t			max_speed_delta_khz;
 	uint32_t			vdd_switch_time_us;
 	unsigned long			max_axi_khz;
-	unsigned long			wait_for_irq_khz;
 	struct clk			*ebi1_clk;
 };
 
@@ -120,8 +121,6 @@
 static struct clock_state drv_state = { 0 };
 static struct clkctl_acpu_speed *acpu_freq_tbl;
 
-static void __init acpuclk_init(void);
-
 /*
  * ACPU freq tables used for different PLLs frequency combinations. The
  * correct table is selected during init.
@@ -484,23 +483,6 @@
  * ARM11 'owned' clock control
  *---------------------------------------------------------------------------*/
 
-#define POWER_COLLAPSE_KHZ 19200
-unsigned long acpuclk_power_collapse(void)
-{
-	int ret = acpuclk_get_rate(smp_processor_id());
-	acpuclk_set_rate(smp_processor_id(), POWER_COLLAPSE_KHZ, SETRATE_PC);
-	return ret;
-}
-
-unsigned long acpuclk_wait_for_irq(void)
-{
-	int rate = acpuclk_get_rate(smp_processor_id());
-	if (rate > MAX_WAIT_FOR_IRQ_KHZ)
-		acpuclk_set_rate(smp_processor_id(), drv_state.wait_for_irq_khz,
-				 SETRATE_SWFI);
-	return rate;
-}
-
 static int acpuclk_set_vdd_level(int vdd)
 {
 	uint32_t current_vdd;
@@ -575,7 +557,8 @@
 	}
 }
 
-int acpuclk_set_rate(int cpu, unsigned long rate, enum setrate_reason reason)
+static int acpuclk_7201_set_rate(int cpu, unsigned long rate,
+				 enum setrate_reason reason)
 {
 	uint32_t reg_clkctl;
 	struct clkctl_acpu_speed *cur_s, *tgt_s, *strt_s;
@@ -587,7 +570,7 @@
 
 	strt_s = cur_s = drv_state.current_speed;
 
-	WARN_ONCE(cur_s == NULL, "acpuclk_set_rate: not initialized\n");
+	WARN_ONCE(cur_s == NULL, "%s: not initialized\n", __func__);
 	if (cur_s == NULL) {
 		rc = -ENOENT;
 		goto out;
@@ -751,7 +734,7 @@
 	return rc;
 }
 
-static void __init acpuclk_init(void)
+static void __init acpuclk_hw_init(void)
 {
 	struct clkctl_acpu_speed *speed;
 	uint32_t div, sel, reg_clksel;
@@ -811,21 +794,16 @@
 	pr_info("ACPU running at %d KHz\n", speed->a11clk_khz);
 }
 
-unsigned long acpuclk_get_rate(int cpu)
+static unsigned long acpuclk_7201_get_rate(int cpu)
 {
 	WARN_ONCE(drv_state.current_speed == NULL,
-		  "acpuclk_get_rate: not initialized\n");
+		  "%s: not initialized\n", __func__);
 	if (drv_state.current_speed)
 		return drv_state.current_speed->a11clk_khz;
 	else
 		return 0;
 }
 
-uint32_t acpuclk_get_switch_time(void)
-{
-	return drv_state.acpu_switch_time_us;
-}
-
 /*----------------------------------------------------------------------------
  * Clock driver initialization
  *---------------------------------------------------------------------------*/
@@ -1080,29 +1058,39 @@
 	pr_warning("Falling back to proc_comm PLL control.\n");
 }
 
-void __init msm_acpu_clock_init(struct msm_acpu_clock_platform_data *clkdata)
+static struct acpuclk_data acpuclk_7201_data = {
+	.set_rate = acpuclk_7201_set_rate,
+	.get_rate = acpuclk_7201_get_rate,
+	.power_collapse_khz = POWER_COLLAPSE_KHZ,
+};
+
+int __init acpuclk_7201_init(struct acpuclk_platform_data *clkdata)
 {
-	pr_info("acpu_clock_init()\n");
+	pr_info("%s()\n", __func__);
 
 	drv_state.ebi1_clk = clk_get(NULL, "ebi1_acpu_clk");
 	BUG_ON(IS_ERR(drv_state.ebi1_clk));
 
 	mutex_init(&drv_state.lock);
 	shared_pll_control_init();
+	acpuclk_7201_data.switch_time_us = clkdata->acpu_switch_time_us;
 	drv_state.acpu_switch_time_us = clkdata->acpu_switch_time_us;
 	drv_state.max_speed_delta_khz = clkdata->max_speed_delta_khz;
 	drv_state.vdd_switch_time_us = clkdata->vdd_switch_time_us;
 	drv_state.max_axi_khz = clkdata->max_axi_khz;
 	acpu_freq_tbl_fixup();
-	drv_state.wait_for_irq_khz = find_wait_for_irq_khz();
+	acpuclk_7201_data.wait_for_irq_khz = find_wait_for_irq_khz();
 	precompute_stepping();
 	if (cpu_is_msm7x25())
 		msm7x25_acpu_pll_hw_bug_fix();
-	acpuclk_init();
+	acpuclk_hw_init();
 	lpj_init();
 	print_acpu_freq_tbl();
+	acpuclk_register(&acpuclk_7201_data);
+
 #ifdef CONFIG_CPU_FREQ_MSM
 	cpufreq_table_init();
 	cpufreq_frequency_table_get_attr(freq_table, smp_processor_id());
 #endif
+	return 0;
 }
diff --git a/arch/arm/mach-msm/acpuclock-7x30.c b/arch/arm/mach-msm/acpuclock-7x30.c
index 2180a8d..0da4322 100644
--- a/arch/arm/mach-msm/acpuclock-7x30.c
+++ b/arch/arm/mach-msm/acpuclock-7x30.c
@@ -56,7 +56,6 @@
 struct clock_state {
 	struct clkctl_acpu_speed	*current_speed;
 	struct mutex			lock;
-	uint32_t			acpu_switch_time_us;
 	uint32_t			vdd_switch_time_us;
 	struct clk			*ebi1_clk;
 };
@@ -133,22 +132,6 @@
 	{ 0 }
 };
 
-#define POWER_COLLAPSE_KHZ MAX_AXI_KHZ
-unsigned long acpuclk_power_collapse(void)
-{
-	int ret = acpuclk_get_rate(smp_processor_id());
-	acpuclk_set_rate(smp_processor_id(), POWER_COLLAPSE_KHZ, SETRATE_PC);
-	return ret;
-}
-
-#define WAIT_FOR_IRQ_KHZ MAX_AXI_KHZ
-unsigned long acpuclk_wait_for_irq(void)
-{
-	int ret = acpuclk_get_rate(smp_processor_id());
-	acpuclk_set_rate(smp_processor_id(), WAIT_FOR_IRQ_KHZ, SETRATE_SWFI);
-	return ret;
-}
-
 static int acpuclk_set_acpu_vdd(struct clkctl_acpu_speed *s)
 {
 	int ret = msm_spm_set_vdd(0, s->vdd_raw);
@@ -207,7 +190,8 @@
 	mb();
 }
 
-int acpuclk_set_rate(int cpu, unsigned long rate, enum setrate_reason reason)
+static int acpuclk_7x30_set_rate(int cpu, unsigned long rate,
+				 enum setrate_reason reason)
 {
 	struct clkctl_acpu_speed *tgt_s, *strt_s;
 	int res, rc = 0;
@@ -320,7 +304,7 @@
 	return rc;
 }
 
-unsigned long acpuclk_get_rate(int cpu)
+static unsigned long acpuclk_7x30_get_rate(int cpu)
 {
 	WARN_ONCE(drv_state.current_speed == NULL,
 		  "acpuclk_get_rate: not initialized\n");
@@ -330,16 +314,11 @@
 		return 0;
 }
 
-uint32_t acpuclk_get_switch_time(void)
-{
-	return drv_state.acpu_switch_time_us;
-}
-
 /*----------------------------------------------------------------------------
  * Clock driver initialization
  *---------------------------------------------------------------------------*/
 
-static void __init acpuclk_init(void)
+static void __init acpuclk_hw_init(void)
 {
 	struct clkctl_acpu_speed *s;
 	uint32_t div, sel, src_num;
@@ -487,16 +466,26 @@
 	BUG_ON(IS_ERR(acpuclk_sources[PLL_3]));
 }
 
-void __init msm_acpu_clock_init(struct msm_acpu_clock_platform_data *clkdata)
+static struct acpuclk_data acpuclk_7x30_data = {
+	.set_rate = acpuclk_7x30_set_rate,
+	.get_rate = acpuclk_7x30_get_rate,
+	.power_collapse_khz = MAX_AXI_KHZ,
+	.wait_for_irq_khz = MAX_AXI_KHZ,
+};
+
+int __init acpuclk_7x30_init(struct acpuclk_platform_data *clkdata)
 {
-	pr_info("acpu_clock_init()\n");
+	pr_info("%s()\n", __func__);
 
 	mutex_init(&drv_state.lock);
-	drv_state.acpu_switch_time_us = clkdata->acpu_switch_time_us;
+	acpuclk_7x30_data.switch_time_us = clkdata->acpu_switch_time_us;
 	drv_state.vdd_switch_time_us = clkdata->vdd_switch_time_us;
 	pll2_fixup();
 	populate_plls();
-	acpuclk_init();
+	acpuclk_hw_init();
 	lpj_init();
 	setup_cpufreq_table();
+	acpuclk_register(&acpuclk_7x30_data);
+
+	return 0;
 }
diff --git a/arch/arm/mach-msm/acpuclock-8960.c b/arch/arm/mach-msm/acpuclock-8960.c
index edac8bb..19dbb8a 100644
--- a/arch/arm/mach-msm/acpuclock-8960.c
+++ b/arch/arm/mach-msm/acpuclock-8960.c
@@ -359,30 +359,11 @@
 	{ 0, { 0 } }
 };
 
-unsigned long acpuclk_get_rate(int cpu)
+static unsigned long acpuclk_8960_get_rate(int cpu)
 {
 	return scalable[cpu].current_speed->khz;
 }
 
-uint32_t acpuclk_get_switch_time(void)
-{
-	return 0;
-}
-
-unsigned long acpuclk_power_collapse(void)
-{
-	int ret = acpuclk_get_rate(smp_processor_id());
-	acpuclk_set_rate(smp_processor_id(), STBY_KHZ, SETRATE_PC);
-	return ret;
-}
-
-unsigned long acpuclk_wait_for_irq(void)
-{
-	int ret = acpuclk_get_rate(smp_processor_id());
-	acpuclk_set_rate(smp_processor_id(), STBY_KHZ, SETRATE_SWFI);
-	return ret;
-}
-
 /* Read an 'indirectly' addressed L2 CP15 register. */
 static uint32_t readl_cp15_l2ind(uint32_t addr)
 {
@@ -758,7 +739,8 @@
 }
 
 /* Set the CPU's clock rate and adjust the L2 rate, if appropriate. */
-int acpuclk_set_rate(int cpu, unsigned long rate, enum setrate_reason reason)
+static int acpuclk_8960_set_rate(int cpu, unsigned long rate,
+				 enum setrate_reason reason)
 {
 	struct core_speed *strt_acpu_s, *tgt_acpu_s;
 	struct l2_level *tgt_l2_l;
@@ -814,7 +796,7 @@
 	/*
 	 * Update the L2 vote and apply the rate change. A spinlock is
 	 * necessary to ensure L2 rate is calulated and set atomically,
-	 * even if acpuclk_set_rate() is called from an atomic context
+	 * even if acpuclk_8960_set_rate() is called from an atomic context
 	 * and the driver_lock mutex is not acquired.
 	 */
 	spin_lock_irqsave(&l2_lock, flags);
@@ -925,8 +907,8 @@
 	sc->current_speed = tgt_s;
 
 	/*
-	 * Set this flag so that the first call to acpuclk_set_rate() can drop
-	 * voltages and set initial bus bandwidth requests.
+	 * Set this flag so that the first call to acpuclk_8960_set_rate() can
+	 * drop voltages and set initial bus bandwidth requests.
 	 */
 	sc->first_set_call = true;
 }
@@ -1016,17 +998,17 @@
 		break;
 	case CPU_DEAD:
 	case CPU_DEAD_FROZEN:
-		prev_khz[cpu] = acpuclk_get_rate(cpu);
+		prev_khz[cpu] = acpuclk_8960_get_rate(cpu);
 		/* Fall through. */
 	case CPU_UP_CANCELED:
 	case CPU_UP_CANCELED_FROZEN:
-		acpuclk_set_rate(cpu, HOT_UNPLUG_KHZ, SETRATE_HOTPLUG);
+		acpuclk_8960_set_rate(cpu, HOT_UNPLUG_KHZ, SETRATE_HOTPLUG);
 		break;
 	case CPU_UP_PREPARE:
 	case CPU_UP_PREPARE_FROZEN:
 		if (WARN_ON(!prev_khz[cpu]))
 			prev_khz[cpu] = acpu_freq_tbl->speed.khz;
-		acpuclk_set_rate(cpu, prev_khz[cpu], SETRATE_HOTPLUG);
+		acpuclk_8960_set_rate(cpu, prev_khz[cpu], SETRATE_HOTPLUG);
 		break;
 	case CPU_STARTING:
 	case CPU_STARTING_FROZEN:
@@ -1046,7 +1028,14 @@
 	.notifier_call = acpuclock_cpu_callback,
 };
 
-void __init msm_acpu_clock_init(struct msm_acpu_clock_platform_data *clkdata)
+static struct acpuclk_data acpuclk_8960_data = {
+	.set_rate = acpuclk_8960_set_rate,
+	.get_rate = acpuclk_8960_get_rate,
+	.power_collapse_khz = STBY_KHZ,
+	.wait_for_irq_khz = STBY_KHZ,
+};
+
+int __init acpuclk_8960_init(struct acpuclk_platform_data *data)
 {
 	if (cpu_is_msm8960()) {
 		scalable = scalable_8960;
@@ -1070,5 +1059,9 @@
 	regulator_init();
 	bus_init();
 	cpufreq_table_init();
+
+	acpuclk_register(&acpuclk_8960_data);
 	register_hotcpu_notifier(&acpuclock_cpu_notifier);
+
+	return 0;
 }
diff --git a/arch/arm/mach-msm/acpuclock-8x50.c b/arch/arm/mach-msm/acpuclock-8x50.c
index 1b2416a..be0cf5b 100644
--- a/arch/arm/mach-msm/acpuclock-8x50.c
+++ b/arch/arm/mach-msm/acpuclock-8x50.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-2011, 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
@@ -114,11 +114,11 @@
 /* Use 128MHz for PC since ACPU will auto-switch to AXI (128MHz) before
  * coming back up. This allows detection of return-from-PC, since 128MHz
  * is only used for power collapse. */
-#define POWER_COLLAPSE_KHZ (AXI_S->acpuclk_khz)
+#define POWER_COLLAPSE_KHZ	128000
 /* Use 245MHz (not 128MHz) for SWFI to avoid unnecessary steps between
  * 128MHz<->245MHz. Jumping to high frequencies from 128MHz directly
  * is not allowed. */
-#define WAIT_FOR_IRQ_KHZ (PLL0_S->acpuclk_khz)
+#define WAIT_FOR_IRQ_KHZ	245760
 
 #ifdef CONFIG_CPU_FREQ_MSM
 static struct cpufreq_frequency_table freq_table[20];
@@ -155,8 +155,6 @@
 struct clock_state {
 	struct clkctl_acpu_speed	*current_speed;
 	struct mutex			lock;
-	uint32_t			acpu_switch_time_us;
-	uint32_t			max_speed_delta_khz;
 	uint32_t			vdd_switch_time_us;
 	unsigned int			max_vdd;
 	struct clk			*ebi1_clk;
@@ -391,7 +389,8 @@
 	}
 }
 
-int acpuclk_set_rate(int cpu, unsigned long rate, enum setrate_reason reason)
+static int acpuclk_8x50_set_rate(int cpu, unsigned long rate,
+				 enum setrate_reason reason)
 {
 	struct clkctl_acpu_speed *tgt_s, *strt_s;
 	int res, rc = 0;
@@ -500,7 +499,7 @@
 	return rc;
 }
 
-static void __init acpuclk_init(void)
+static void __init acpuclk_hw_init(void)
 {
 	struct clkctl_acpu_speed *speed;
 	uint32_t div, sel, regval;
@@ -567,30 +566,11 @@
 	pr_info("ACPU running at %d KHz\n", speed->acpuclk_khz);
 }
 
-unsigned long acpuclk_get_rate(int cpu)
+static unsigned long acpuclk_8x50_get_rate(int cpu)
 {
 	return drv_state.current_speed->acpuclk_khz;
 }
 
-uint32_t acpuclk_get_switch_time(void)
-{
-	return drv_state.acpu_switch_time_us;
-}
-
-unsigned long acpuclk_power_collapse(void)
-{
-	int ret = acpuclk_get_rate(smp_processor_id());
-	acpuclk_set_rate(smp_processor_id(), POWER_COLLAPSE_KHZ, SETRATE_PC);
-	return ret;
-}
-
-unsigned long acpuclk_wait_for_irq(void)
-{
-	int ret = acpuclk_get_rate(smp_processor_id());
-	acpuclk_set_rate(smp_processor_id(), WAIT_FOR_IRQ_KHZ, SETRATE_SWFI);
-	return ret;
-}
-
 /* Spare register populated with efuse data on max ACPU freq. */
 #define CT_CSR_PHYS		0xA8700000
 #define TCSR_SPARE2_ADDR	(ct_csr_base + 0x60)
@@ -689,11 +669,17 @@
 }
 #endif
 
-void __init msm_acpu_clock_init(struct msm_acpu_clock_platform_data *clkdata)
+static struct acpuclk_data acpuclk_8x50_data = {
+	.set_rate = acpuclk_8x50_set_rate,
+	.get_rate = acpuclk_8x50_get_rate,
+	.power_collapse_khz = POWER_COLLAPSE_KHZ,
+	.wait_for_irq_khz = WAIT_FOR_IRQ_KHZ,
+};
+
+int __init acpuclk_8x50_init(struct acpuclk_platform_data *clkdata)
 {
 	mutex_init(&drv_state.lock);
-	drv_state.acpu_switch_time_us = clkdata->acpu_switch_time_us;
-	drv_state.max_speed_delta_khz = clkdata->max_speed_delta_khz;
+	acpuclk_8x50_data.switch_time_us = clkdata->acpu_switch_time_us;
 	drv_state.vdd_switch_time_us = clkdata->vdd_switch_time_us;
 	drv_state.max_vdd = clkdata->max_vdd;
 	drv_state.acpu_set_vdd = clkdata->acpu_set_vdd;
@@ -702,13 +688,15 @@
 	BUG_ON(IS_ERR(drv_state.ebi1_clk));
 
 	acpu_freq_tbl_fixup();
-	acpuclk_init();
+	acpuclk_hw_init();
 	lpj_init();
 	/* Set a lower bound for ACPU rate for boot. This limits the
 	 * maximum frequency hop caused by the first CPUFREQ switch. */
 	if (drv_state.current_speed->acpuclk_khz < PLL0_S->acpuclk_khz)
 		acpuclk_set_rate(0, PLL0_S->acpuclk_khz, SETRATE_CPUFREQ);
 
+	acpuclk_register(&acpuclk_8x50_data);
+
 #ifdef CONFIG_CPU_FREQ_MSM
 	cpufreq_table_init();
 	cpufreq_frequency_table_get_attr(freq_table, smp_processor_id());
@@ -720,4 +708,5 @@
 		drv_state.acpu_set_vdd = NULL;
 	}
 #endif
+	return 0;
 }
diff --git a/arch/arm/mach-msm/acpuclock-8x60.c b/arch/arm/mach-msm/acpuclock-8x60.c
index d840865..b7d0589 100644
--- a/arch/arm/mach-msm/acpuclock-8x60.c
+++ b/arch/arm/mach-msm/acpuclock-8x60.c
@@ -115,9 +115,6 @@
 	struct clkctl_l2_speed		*current_l2_speed;
 	spinlock_t			l2_lock;
 	struct mutex			lock;
-	uint32_t			acpu_switch_time_us;
-	uint32_t			vdd_switch_time_us;
-	uint32_t			max_speed_delta_khz;
 } drv_state;
 
 struct clkctl_l2_speed {
@@ -318,32 +315,11 @@
 static struct clkctl_l2_speed *l2_freq_tbl = l2_freq_tbl_v2;
 static unsigned int l2_freq_tbl_size = ARRAY_SIZE(l2_freq_tbl_v2);
 
-unsigned long acpuclk_get_rate(int cpu)
+static unsigned long acpuclk_8x60_get_rate(int cpu)
 {
 	return drv_state.current_speed[cpu]->acpuclk_khz;
 }
 
-uint32_t acpuclk_get_switch_time(void)
-{
-	return drv_state.acpu_switch_time_us;
-}
-
-#define POWER_COLLAPSE_KHZ MAX_AXI
-unsigned long acpuclk_power_collapse(void)
-{
-	int ret = acpuclk_get_rate(smp_processor_id());
-	acpuclk_set_rate(smp_processor_id(), POWER_COLLAPSE_KHZ, SETRATE_PC);
-	return ret;
-}
-
-#define WAIT_FOR_IRQ_KHZ MAX_AXI
-unsigned long acpuclk_wait_for_irq(void)
-{
-	int ret = acpuclk_get_rate(smp_processor_id());
-	acpuclk_set_rate(smp_processor_id(), WAIT_FOR_IRQ_KHZ, SETRATE_SWFI);
-	return ret;
-}
-
 static void select_core_source(unsigned int id, unsigned int src)
 {
 	uint32_t regval;
@@ -595,7 +571,8 @@
 	drv_state.current_speed[cpu] = tgt_s;
 }
 
-int acpuclk_set_rate(int cpu, unsigned long rate, enum setrate_reason reason)
+static int acpuclk_8x60_set_rate(int cpu, unsigned long rate,
+				 enum setrate_reason reason)
 {
 	struct clkctl_acpu_speed *tgt_s, *strt_s;
 	struct clkctl_l2_speed *tgt_l2;
@@ -859,17 +836,17 @@
 	switch (action) {
 	case CPU_DEAD:
 	case CPU_DEAD_FROZEN:
-		prev_khz[cpu] = acpuclk_get_rate(cpu);
+		prev_khz[cpu] = acpuclk_8x60_get_rate(cpu);
 		/* Fall through. */
 	case CPU_UP_CANCELED:
 	case CPU_UP_CANCELED_FROZEN:
-		acpuclk_set_rate(cpu, HOT_UNPLUG_KHZ, SETRATE_HOTPLUG);
+		acpuclk_8x60_set_rate(cpu, HOT_UNPLUG_KHZ, SETRATE_HOTPLUG);
 		break;
 	case CPU_UP_PREPARE:
 	case CPU_UP_PREPARE_FROZEN:
 		if (WARN_ON(!prev_khz[cpu]))
 			prev_khz[cpu] = acpu_freq_tbl->acpuclk_khz;
-		acpuclk_set_rate(cpu, prev_khz[cpu], SETRATE_HOTPLUG);
+		acpuclk_8x60_set_rate(cpu, prev_khz[cpu], SETRATE_HOTPLUG);
 		break;
 	default:
 		break;
@@ -936,15 +913,20 @@
 	return f->acpuclk_khz;
 }
 
-void __init msm_acpu_clock_init(struct msm_acpu_clock_platform_data *clkdata)
+static struct acpuclk_data acpuclk_8x60_data = {
+	.set_rate = acpuclk_8x60_set_rate,
+	.get_rate = acpuclk_8x60_get_rate,
+	.power_collapse_khz = MAX_AXI,
+	.wait_for_irq_khz = MAX_AXI,
+};
+
+int __init acpuclk_8x60_init(struct acpuclk_platform_data *clkdata)
 {
 	unsigned int max_cpu_khz;
 	int cpu;
 
 	mutex_init(&drv_state.lock);
 	spin_lock_init(&drv_state.l2_lock);
-	drv_state.acpu_switch_time_us = clkdata->acpu_switch_time_us;
-	drv_state.vdd_switch_time_us = clkdata->vdd_switch_time_us;
 
 	/* Configure hardware. */
 	max_cpu_khz = select_freq_plan();
@@ -958,8 +940,11 @@
 
 	/* Improve boot time by ramping up CPUs immediately. */
 	for_each_online_cpu(cpu)
-		acpuclk_set_rate(cpu, max_cpu_khz, SETRATE_INIT);
+		acpuclk_8x60_set_rate(cpu, max_cpu_khz, SETRATE_INIT);
 
+	acpuclk_register(&acpuclk_8x60_data);
 	cpufreq_table_init();
 	register_hotcpu_notifier(&acpuclock_cpu_notifier);
+
+	return 0;
 }
diff --git a/arch/arm/mach-msm/acpuclock-fsm9xxx.c b/arch/arm/mach-msm/acpuclock-fsm9xxx.c
index b12eb9e..4acae13 100644
--- a/arch/arm/mach-msm/acpuclock-fsm9xxx.c
+++ b/arch/arm/mach-msm/acpuclock-fsm9xxx.c
@@ -20,7 +20,7 @@
 /* Registers */
 #define PLL1_CTL_ADDR		(MSM_CLK_CTL_BASE + 0x604)
 
-unsigned long acpuclk_get_rate(int cpu)
+static unsigned long acpuclk_9xxx_get_rate(int cpu)
 {
 	unsigned int pll1_ctl;
 	unsigned int pll1_l, pll1_div2;
@@ -36,7 +36,13 @@
 	return pll1_khz;
 }
 
-void __init msm_acpu_clock_init(struct msm_acpu_clock_platform_data *clkdata)
+static struct acpuclk_data acpuclk_9xxx_data = {
+	.get_rate = acpuclk_9xxx_get_rate,
+};
+
+int __init acpuclk_9xxx_init(struct acpuclk_platform_data *clkdata)
 {
+	acpuclk_register(&acpuclk_9xxx_data);
 	pr_info("ACPU running at %lu KHz\n", acpuclk_get_rate(0));
+	return 0;
 }
diff --git a/arch/arm/mach-msm/acpuclock.c b/arch/arm/mach-msm/acpuclock.c
new file mode 100644
index 0000000..4aced18
--- /dev/null
+++ b/arch/arm/mach-msm/acpuclock.c
@@ -0,0 +1,75 @@
+/* Copyright (c) 2011, 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.
+ */
+
+#include <linux/cpu.h>
+#include "acpuclock.h"
+
+static struct acpuclk_data *acpuclk_data;
+
+unsigned long acpuclk_get_rate(int cpu)
+{
+	if (!acpuclk_data->get_rate)
+		return 0;
+
+	return acpuclk_data->get_rate(cpu);
+}
+
+int acpuclk_set_rate(int cpu, unsigned long rate, enum setrate_reason reason)
+{
+	if (!acpuclk_data->set_rate)
+		return 0;
+
+	return acpuclk_data->set_rate(cpu, rate, reason);
+}
+
+uint32_t acpuclk_get_switch_time(void)
+{
+	return acpuclk_data->switch_time_us;
+}
+
+unsigned long acpuclk_power_collapse(void)
+{
+	unsigned long rate = acpuclk_get_rate(smp_processor_id());
+	acpuclk_set_rate(smp_processor_id(), acpuclk_data->power_collapse_khz,
+			 SETRATE_PC);
+	return rate;
+}
+
+unsigned long acpuclk_wait_for_irq(void)
+{
+	unsigned long rate = acpuclk_get_rate(smp_processor_id());
+	acpuclk_set_rate(smp_processor_id(), acpuclk_data->wait_for_irq_khz,
+			 SETRATE_SWFI);
+	return rate;
+}
+
+void __init acpuclk_register(struct acpuclk_data *data)
+{
+	acpuclk_data = data;
+}
+
+int __init acpuclk_init(struct acpuclk_platform_data *pdata)
+{
+	int rc;
+
+	if (!pdata->init)
+		return -EINVAL;
+
+	rc = pdata->init(pdata);
+	if (rc)
+		return rc;
+
+	if (!acpuclk_data)
+		return -ENODEV;
+
+	return 0;
+}
diff --git a/arch/arm/mach-msm/acpuclock.h b/arch/arm/mach-msm/acpuclock.h
index 6fa2e3b..4a8bf29 100644
--- a/arch/arm/mach-msm/acpuclock.h
+++ b/arch/arm/mach-msm/acpuclock.h
@@ -1,9 +1,8 @@
-/* arch/arm/mach-msm/acpuclock.h
- *
- * MSM architecture clock driver header
+/*
+ * MSM architecture CPU clock driver header
  *
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2007-2010, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2007-2011, Code Aurora Forum. All rights reserved.
  * Author: San Mehat <san@android.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -20,8 +19,9 @@
 #ifndef __ARCH_ARM_MACH_MSM_ACPUCLOCK_H
 #define __ARCH_ARM_MACH_MSM_ACPUCLOCK_H
 
-#include <linux/list.h>
-
+/**
+ * enum setrate_reason - Reasons for use with acpuclk_set_rate()
+ */
 enum setrate_reason {
 	SETRATE_CPUFREQ = 0,
 	SETRATE_SWFI,
@@ -30,10 +30,84 @@
 	SETRATE_INIT,
 };
 
-int acpuclk_set_rate(int cpu, unsigned long rate, enum setrate_reason reason);
+/**
+ * struct acpuclk_platform_data - Platform data for acpuclk_init()
+ */
+struct acpuclk_platform_data {
+	uint32_t acpu_switch_time_us;
+	unsigned long max_speed_delta_khz;
+	uint32_t vdd_switch_time_us;
+	unsigned int max_axi_khz;
+	unsigned int max_vdd;
+	int (*acpu_set_vdd) (int mvolts);
+	int (*init)(struct acpuclk_platform_data *);
+};
+
+/**
+ * struct acpuclk_data - Function pointers and data for function implementations
+ */
+struct acpuclk_data {
+	unsigned long (*get_rate)(int cpu);
+	int (*set_rate)(int cpu, unsigned long rate, enum setrate_reason);
+	uint32_t switch_time_us;
+	unsigned long power_collapse_khz;
+	unsigned long wait_for_irq_khz;
+};
+
+/**
+ * acpulock_get_rate() - Get a CPU's clock rate in KHz
+ * @cpu: CPU to query the rate of
+ */
 unsigned long acpuclk_get_rate(int cpu);
+
+/**
+ * acpuclk_set_rate() - Set a CPU's clock rate
+ * @cpu: CPU to set rate of
+ * @rate: Desired rate in KHz
+ * @setrate_reason: Reason for the rate switch
+ *
+ * Returns 0 for success.
+ */
+int acpuclk_set_rate(int cpu, unsigned long rate, enum setrate_reason);
+
+/**
+ * acpuclk_get_switch_time() - Query estimated time in us for a CPU rate switch
+ */
 uint32_t acpuclk_get_switch_time(void);
-unsigned long acpuclk_wait_for_irq(void);
+
+/**
+ * acpuclk_power_collapse() - Prepare current CPU clocks for power-collapse
+ *
+ * Returns the previous rate of the CPU in KHz.
+ */
 unsigned long acpuclk_power_collapse(void);
 
+/**
+ * acpuclk_wait_for_irq() - Prepare current CPU clocks for SWFI
+ *
+ * Returns the previous rate of the CPU in KHz.
+ */
+unsigned long acpuclk_wait_for_irq(void);
+
+/**
+ * acpuclk_register() - Register acpuclk_data function implementations
+ * @data: acpuclock API implementations and data
+ */
+void acpuclk_register(struct acpuclk_data *data);
+
+/**
+ * acpuclk_init() - acpuclock driver initialization function
+ *
+ * Return 0 for success.
+ */
+int acpuclk_init(struct acpuclk_platform_data *);
+
+/* SoC-specific acpuclock initialization functions. */
+int acpuclk_7201_init(struct acpuclk_platform_data *);
+int acpuclk_7x30_init(struct acpuclk_platform_data *);
+int acpuclk_8x50_init(struct acpuclk_platform_data *);
+int acpuclk_8x60_init(struct acpuclk_platform_data *);
+int acpuclk_8960_init(struct acpuclk_platform_data *);
+int acpuclk_9xxx_init(struct acpuclk_platform_data *);
+
 #endif
diff --git a/arch/arm/mach-msm/board-fsm9xxx.c b/arch/arm/mach-msm/board-fsm9xxx.c
index 0053734..9c1e72ff 100644
--- a/arch/arm/mach-msm/board-fsm9xxx.c
+++ b/arch/arm/mach-msm/board-fsm9xxx.c
@@ -39,6 +39,7 @@
 #include <mach/socinfo.h>
 #include "devices.h"
 #include "timer.h"
+#include "acpuclock.h"
 #include "pm.h"
 #include "spm.h"
 #include <linux/regulator/consumer.h>
@@ -834,9 +835,10 @@
 	&fsm_xo_device,
 };
 
-static struct msm_acpu_clock_platform_data fsm9xxx_clock_data = {
+static struct acpuclk_platform_data fsm9xxx_clock_data __initdata = {
 	.acpu_switch_time_us = 50,
 	.vdd_switch_time_us = 62,
+	.init = acpuclk_9xxx_init,
 };
 
 static void __init fsm9xxx_init_irq(void)
@@ -877,7 +879,7 @@
 		pr_err("%s: socinfo_init() failed!\n",
 		       __func__);
 
-	msm_acpu_clock_init(&fsm9xxx_clock_data);
+	acpuclk_init(&fsm9xxx_clock_data);
 
 	regulator_has_full_constraints();
 
diff --git a/arch/arm/mach-msm/board-msm7x27.c b/arch/arm/mach-msm/board-msm7x27.c
index 3959bf2..bf1c4b4 100644
--- a/arch/arm/mach-msm/board-msm7x27.c
+++ b/arch/arm/mach-msm/board-msm7x27.c
@@ -60,6 +60,7 @@
 
 #include "devices.h"
 #include "clock.h"
+#include "acpuclock.h"
 #include "msm-keypad-devices.h"
 #include "pm.h"
 
@@ -1488,11 +1489,12 @@
 	msm_init_irq();
 }
 
-static struct msm_acpu_clock_platform_data msm7x2x_clock_data = {
+static struct acpuclk_platform_data msm7x2x_clock_data __initdata = {
 	.acpu_switch_time_us = 50,
 	.max_speed_delta_khz = 400000,
 	.vdd_switch_time_us = 62,
 	.max_axi_khz = 160000,
+	.init = acpuclk_7201_init,
 };
 
 void msm_serial_debug_init(unsigned int base, int irq,
@@ -1894,7 +1896,7 @@
 	if (cpu_is_msm7x27())
 		msm7x2x_clock_data.max_axi_khz = 200000;
 
-	msm_acpu_clock_init(&msm7x2x_clock_data);
+	acpuclk_init(&msm7x2x_clock_data);
 
 	usb_mpp_init();
 
diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c
index 10dcc68..edebbd8 100644
--- a/arch/arm/mach-msm/board-msm7x30.c
+++ b/arch/arm/mach-msm/board-msm7x30.c
@@ -80,6 +80,7 @@
 #endif
 #include "pm.h"
 #include "spm.h"
+#include "acpuclock.h"
 #include <mach/dal_axi.h>
 #include <mach/msm_serial_hs.h>
 #include <mach/qdsp5v2/mi2s.h>
@@ -5523,9 +5524,10 @@
 };
 #endif
 
-static struct msm_acpu_clock_platform_data msm7x30_clock_data = {
+static struct acpuclk_platform_data msm7x30_clock_data __initdata = {
 	.acpu_switch_time_us = 50,
 	.vdd_switch_time_us = 62,
+	.init = acpuclk_7x30_init,
 };
 
 static void __init msm7x30_init_irq(void)
@@ -6953,7 +6955,7 @@
 	msm7x30_init_uart2();
 #endif
 	msm_spm_init(&msm_spm_data, 1);
-	msm_acpu_clock_init(&msm7x30_clock_data);
+	acpuclk_init(&msm7x30_clock_data);
 	if (machine_is_msm7x30_surf() || machine_is_msm7x30_fluid())
 		msm7x30_cfg_smsc911x();
 
diff --git a/arch/arm/mach-msm/board-msm8960.c b/arch/arm/mach-msm/board-msm8960.c
index 4882772..a135037 100644
--- a/arch/arm/mach-msm/board-msm8960.c
+++ b/arch/arm/mach-msm/board-msm8960.c
@@ -79,6 +79,7 @@
 #include "cpuidle.h"
 #include "rpm_resources.h"
 #include "mpm.h"
+#include "acpuclock.h"
 
 static struct platform_device msm_fm_platform_init = {
 	.name = "iris_fm",
@@ -1930,9 +1931,10 @@
 	return 0;
 }
 
-static struct msm_acpu_clock_platform_data msm8960_acpu_clock_data = {
+static struct acpuclk_platform_data msm8960_acpuclk_data __initdata = {
 	.acpu_switch_time_us = 0,
 	.vdd_switch_time_us = 0,
+	.init = acpuclk_8960_init,
 };
 
 #define MSM_SHARED_RAM_PHYS 0x80000000
@@ -3510,7 +3512,7 @@
 	platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
 	pm8921_gpio_mpp_init();
 	platform_add_devices(sim_devices, ARRAY_SIZE(sim_devices));
-	msm_acpu_clock_init(&msm8960_acpu_clock_data);
+	acpuclk_init(&msm8960_acpuclk_data);
 
 	msm8960_device_qup_spi_gsbi1.dev.platform_data =
 				&msm8960_qup_spi_gsbi1_pdata;
@@ -3601,7 +3603,7 @@
 	platform_add_devices(cdp_devices, ARRAY_SIZE(cdp_devices));
 	msm8960_init_cam();
 	msm8960_init_mmc();
-	msm_acpu_clock_init(&msm8960_acpu_clock_data);
+	acpuclk_init(&msm8960_acpuclk_data);
 	register_i2c_devices();
 	msm8960_wcnss_init();
 	msm_fb_add_devices();
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index 0f82943..792f42b 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -102,6 +102,7 @@
 #include "peripheral-loader.h"
 #include <linux/platform_data/qcom_crypto_device.h>
 #include "rpm_resources.h"
+#include "acpuclock.h"
 
 #define MSM_SHARED_RAM_PHYS 0x40000000
 
@@ -397,7 +398,8 @@
 	},
 };
 
-static struct msm_acpu_clock_platform_data msm8x60_acpu_clock_data = {
+static struct acpuclk_platform_data msm8x60_acpuclk_data __initdata = {
+	.init = acpuclk_8x60_init,
 };
 
 /*
@@ -10058,7 +10060,7 @@
 	platform_add_devices(early_devices, ARRAY_SIZE(early_devices));
 	/* CPU frequency control is not supported on simulated targets. */
 	if (!machine_is_msm8x60_rumi3() && !machine_is_msm8x60_sim())
-		msm_acpu_clock_init(&msm8x60_acpu_clock_data);
+		acpuclk_init(&msm8x60_acpuclk_data);
 
 	/* No EBI2 on 8660 charm targets */
 	if (!machine_is_msm8x60_fusion() && !machine_is_msm8x60_fusn_ffa())
diff --git a/arch/arm/mach-msm/board-qsd8x50.c b/arch/arm/mach-msm/board-qsd8x50.c
index e8f394a..c99dc6d 100644
--- a/arch/arm/mach-msm/board-qsd8x50.c
+++ b/arch/arm/mach-msm/board-qsd8x50.c
@@ -54,6 +54,7 @@
 #include "devices.h"
 #include "timer.h"
 #include "msm-keypad-devices.h"
+#include "acpuclock.h"
 #include "pm.h"
 #include "proc_comm.h"
 #ifdef CONFIG_USB_ANDROID
@@ -1239,12 +1240,13 @@
 	return rc;
 }
 
-static struct msm_acpu_clock_platform_data qsd8x50_clock_data = {
+static struct acpuclk_platform_data qsd8x50_clock_data __initdata = {
 	.acpu_switch_time_us = 20,
 	.max_speed_delta_khz = 256000,
 	.vdd_switch_time_us = 62,
 	.max_vdd = TPS65023_MAX_DCDC1,
 	.acpu_set_vdd = qsd8x50_tps65023_set_dcdc1,
+	.init = acpuclk_8x50_init,
 };
 
 
@@ -2442,7 +2444,7 @@
 		       __func__);
 	msm_clock_init(&qds8x50_clock_init_data);
 	qsd8x50_cfg_smc91x();
-	msm_acpu_clock_init(&qsd8x50_clock_data);
+	acpuclk_init(&qsd8x50_clock_data);
 
 	msm_hsusb_pdata.swfi_latency =
 		msm_pm_data
diff --git a/arch/arm/mach-msm/devices-msm7x27a.c b/arch/arm/mach-msm/devices-msm7x27a.c
index 725f47f..fe40248 100644
--- a/arch/arm/mach-msm/devices-msm7x27a.c
+++ b/arch/arm/mach-msm/devices-msm7x27a.c
@@ -29,6 +29,7 @@
 #include "devices.h"
 #include "devices-msm7x2xa.h"
 #include "footswitch.h"
+#include "acpuclock.h"
 
 /* Address of GSBI blocks */
 #define MSM_GSBI0_PHYS		0xA1200000
@@ -694,11 +695,12 @@
 	.id     = 0,
 };
 
-static struct msm_acpu_clock_platform_data msm7x2x_clock_data = {
+static struct acpuclk_platform_data msm7x2x_clock_data __initdata = {
 	.acpu_switch_time_us = 50,
 	.max_speed_delta_khz = 400000,
 	.vdd_switch_time_us = 62,
 	.max_axi_khz = 200000,
+	.init = acpuclk_7201_init,
 };
 
 int __init msm7x2x_misc_init(void)
@@ -710,7 +712,7 @@
 		msm7x2x_clock_data.max_speed_delta_khz = 504000;
 
 	msm_clock_init(&msm7x27a_clock_init_data);
-	msm_acpu_clock_init(&msm7x2x_clock_data);
+	acpuclk_init(&msm7x2x_clock_data);
 
 	return 0;
 }
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index bd0679f..a537b4f 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -28,16 +28,6 @@
 #include <mach/msm_bus.h>
 #endif
 
-/* platform device data structures */
-struct msm_acpu_clock_platform_data {
-	uint32_t acpu_switch_time_us;
-	uint32_t max_speed_delta_khz;
-	uint32_t vdd_switch_time_us;
-	unsigned int max_axi_khz;
-	unsigned int max_vdd;
-	int (*acpu_set_vdd) (int mvolts);
-};
-
 struct msm_camera_io_ext {
 	uint32_t mdcphy;
 	uint32_t mdcsz;
@@ -383,7 +373,6 @@
 void __init msm_map_msm7x30_io(void);
 void __init msm_map_fsm9xxx_io(void);
 void __init msm_init_irq(void);
-void __init msm_acpu_clock_init(struct msm_acpu_clock_platform_data *);
 
 struct mmc_platform_data;
 int __init msm_add_sdcc(unsigned int controller,