msm: clock-rpm: Add support for CXO/PXO clock resources

The CXO_CLK and PXO_CLK resources have historically been
controlled by the msm_xo driver. Add support for these to the
clock driver so that consumers of these clocks can use the clock
APIs instead of an MSM specific API.

Change-Id: I76b8dbcf6bbe26494186f68faff1b2e41ce2c2e3
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
diff --git a/arch/arm/mach-msm/clock-rpm.c b/arch/arm/mach-msm/clock-rpm.c
index 4757f7d..fc2e83f 100644
--- a/arch/arm/mach-msm/clock-rpm.c
+++ b/arch/arm/mach-msm/clock-rpm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, 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
@@ -23,9 +23,9 @@
 static int rpm_clk_enable(struct clk *clk)
 {
 	unsigned long flags;
-	struct msm_rpm_iv_pair iv;
-	int rc = 0;
 	struct rpm_clk *r = to_rpm_clk(clk);
+	struct msm_rpm_iv_pair iv = { .id = r->rpm_clk_id };
+	int rc = 0;
 	unsigned long this_khz, this_sleep_khz;
 	unsigned long peer_khz = 0, peer_sleep_khz = 0;
 	struct rpm_clk *peer = r->peer;
@@ -39,8 +39,6 @@
 
 	this_sleep_khz = r->last_set_sleep_khz;
 
-	iv.id = r->rpm_clk_id;
-
 	/* Take peer clock's rate into account only if it's enabled. */
 	if (peer->enabled) {
 		peer_khz = peer->last_set_khz;
@@ -48,11 +46,16 @@
 	}
 
 	iv.value = max(this_khz, peer_khz);
+	if (r->branch)
+		iv.value = !!iv.value;
+
 	rc = msm_rpmrs_set_noirq(MSM_RPM_CTX_SET_0, &iv, 1);
 	if (rc)
 		goto out;
 
 	iv.value = max(this_sleep_khz, peer_sleep_khz);
+	if (r->branch)
+		iv.value = !!iv.value;
 	rc = msm_rpmrs_set_noirq(MSM_RPM_CTX_SET_SLEEP, &iv, 1);
 	if (rc) {
 		iv.value = peer_khz;
@@ -76,25 +79,23 @@
 	spin_lock_irqsave(&rpm_clock_lock, flags);
 
 	if (r->last_set_khz) {
-		struct msm_rpm_iv_pair iv;
+		struct msm_rpm_iv_pair iv = { .id = r->rpm_clk_id };
 		struct rpm_clk *peer = r->peer;
 		unsigned long peer_khz = 0, peer_sleep_khz = 0;
 		int rc;
 
-		iv.id = r->rpm_clk_id;
-
 		/* Take peer clock's rate into account only if it's enabled. */
 		if (peer->enabled) {
 			peer_khz = peer->last_set_khz;
 			peer_sleep_khz = peer->last_set_sleep_khz;
 		}
 
-		iv.value = peer_khz;
+		iv.value = r->branch ? !!peer_khz : peer_khz;
 		rc = msm_rpmrs_set_noirq(MSM_RPM_CTX_SET_0, &iv, 1);
 		if (rc)
 			goto out;
 
-		iv.value = peer_sleep_khz;
+		iv.value = r->branch ? !!peer_sleep_khz : peer_sleep_khz;
 		rc = msm_rpmrs_set_noirq(MSM_RPM_CTX_SET_SLEEP, &iv, 1);
 	}
 	r->enabled = false;
@@ -186,6 +187,12 @@
 	return false;
 }
 
+static unsigned long rpm_branch_clk_get_rate(struct clk *clk)
+{
+	struct rpm_clk *r = to_rpm_clk(clk);
+	return r->last_set_khz * 1000;
+}
+
 struct clk_ops clk_ops_rpm = {
 	.enable = rpm_clk_enable,
 	.disable = rpm_clk_disable,
@@ -195,3 +202,10 @@
 	.round_rate = rpm_clk_round_rate,
 	.is_local = rpm_clk_is_local,
 };
+
+struct clk_ops clk_ops_rpm_branch = {
+	.enable = rpm_clk_enable,
+	.disable = rpm_clk_disable,
+	.is_local = rpm_clk_is_local,
+	.get_rate = rpm_branch_clk_get_rate,
+};
diff --git a/arch/arm/mach-msm/clock-rpm.h b/arch/arm/mach-msm/clock-rpm.h
index 24df9b6..27afd6f 100644
--- a/arch/arm/mach-msm/clock-rpm.h
+++ b/arch/arm/mach-msm/clock-rpm.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, 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
@@ -18,6 +18,7 @@
 
 struct clk_ops;
 extern struct clk_ops clk_ops_rpm;
+extern struct clk_ops clk_ops_rpm_branch;
 
 struct rpm_clk {
 	const int rpm_clk_id;
@@ -27,6 +28,7 @@
 	/* 0 if active_only. Otherwise, same as last_set_khz. */
 	unsigned last_set_sleep_khz;
 	bool enabled;
+	bool branch; /* true: RPM only accepts 1 for ON and 0 for OFF */
 
 	struct rpm_clk *peer;
 	struct clk c;
@@ -65,4 +67,35 @@
 		}, \
 	};
 
+#define DEFINE_CLK_RPM_BRANCH(name, active, r_id, rate) \
+	static struct rpm_clk active; \
+	static struct rpm_clk name = { \
+		.rpm_clk_id = MSM_RPM_ID_##r_id##_CLK, \
+		.rpm_status_id = MSM_RPM_STATUS_ID_##r_id##_CLK, \
+		.peer = &active, \
+		.last_set_khz = ((rate) / 1000), \
+		.last_set_sleep_khz = ((rate) / 1000), \
+		.branch = true, \
+		.c = { \
+			.ops = &clk_ops_rpm_branch, \
+			.flags = CLKFLAG_SKIP_AUTO_OFF, \
+			.dbg_name = #name, \
+			CLK_INIT(name.c), \
+		}, \
+	}; \
+	static struct rpm_clk active = { \
+		.rpm_clk_id = MSM_RPM_ID_##r_id##_CLK, \
+		.rpm_status_id = MSM_RPM_STATUS_ID_##r_id##_CLK, \
+		.peer = &name, \
+		.last_set_khz = ((rate) / 1000), \
+		.active_only = true, \
+		.branch = true, \
+		.c = { \
+			.ops = &clk_ops_rpm_branch, \
+			.flags = CLKFLAG_SKIP_AUTO_OFF, \
+			.dbg_name = #active, \
+			CLK_INIT(active.c), \
+		}, \
+	};
+
 #endif