diff options
author | Stephen Boyd <sboyd@codeaurora.org> | 2014-01-15 13:47:22 -0500 |
---|---|---|
committer | Mike Turquette <mturquette@linaro.org> | 2014-01-16 15:00:57 -0500 |
commit | 3fa2252b7a78a8057017471a28f47b306e95ee26 (patch) | |
tree | e3cf04e4099a9414b15d27f6428f7726f29d7a05 | |
parent | d0d44dd4ac58bc547646a9d0e65b4648f97cb533 (diff) |
clk: Add set_rate_and_parent() op
Some of Qualcomm's clocks can change their parent and rate at the
same time with a single register write. Add support for this
hardware to the common clock framework by adding a new
set_rate_and_parent() op. When the clock framework determines
that both the parent and the rate are going to change during
clk_set_rate() it will call the .set_rate_and_parent() op if
available and fall back to calling .set_parent() followed by
.set_rate() otherwise.
Reviewed-by: James Hogan <james.hogan@imgtec.com>
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
Signed-off-by: Mike Turquette <mturquette@linaro.org>
-rw-r--r-- | Documentation/clk.txt | 3 | ||||
-rw-r--r-- | drivers/clk/clk.c | 78 | ||||
-rw-r--r-- | include/linux/clk-provider.h | 15 |
3 files changed, 77 insertions, 19 deletions
diff --git a/Documentation/clk.txt b/Documentation/clk.txt index eb20198783cd..699ef2a323b1 100644 --- a/Documentation/clk.txt +++ b/Documentation/clk.txt | |||
@@ -77,6 +77,9 @@ the operations defined in clk.h: | |||
77 | int (*set_parent)(struct clk_hw *hw, u8 index); | 77 | int (*set_parent)(struct clk_hw *hw, u8 index); |
78 | u8 (*get_parent)(struct clk_hw *hw); | 78 | u8 (*get_parent)(struct clk_hw *hw); |
79 | int (*set_rate)(struct clk_hw *hw, unsigned long); | 79 | int (*set_rate)(struct clk_hw *hw, unsigned long); |
80 | int (*set_rate_and_parent)(struct clk_hw *hw, | ||
81 | unsigned long rate, | ||
82 | unsigned long parent_rate, u8 index); | ||
80 | unsigned long (*recalc_accuracy)(struct clk_hw *hw, | 83 | unsigned long (*recalc_accuracy)(struct clk_hw *hw, |
81 | unsigned long parent_accuracy); | 84 | unsigned long parent_accuracy); |
82 | void (*init)(struct clk_hw *hw); | 85 | void (*init)(struct clk_hw *hw); |
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index e3e03270b95e..2b38dc99063f 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c | |||
@@ -1218,10 +1218,9 @@ static void clk_reparent(struct clk *clk, struct clk *new_parent) | |||
1218 | clk->parent = new_parent; | 1218 | clk->parent = new_parent; |
1219 | } | 1219 | } |
1220 | 1220 | ||
1221 | static int __clk_set_parent(struct clk *clk, struct clk *parent, u8 p_index) | 1221 | static struct clk *__clk_set_parent_before(struct clk *clk, struct clk *parent) |
1222 | { | 1222 | { |
1223 | unsigned long flags; | 1223 | unsigned long flags; |
1224 | int ret = 0; | ||
1225 | struct clk *old_parent = clk->parent; | 1224 | struct clk *old_parent = clk->parent; |
1226 | 1225 | ||
1227 | /* | 1226 | /* |
@@ -1252,6 +1251,34 @@ static int __clk_set_parent(struct clk *clk, struct clk *parent, u8 p_index) | |||
1252 | clk_reparent(clk, parent); | 1251 | clk_reparent(clk, parent); |
1253 | clk_enable_unlock(flags); | 1252 | clk_enable_unlock(flags); |
1254 | 1253 | ||
1254 | return old_parent; | ||
1255 | } | ||
1256 | |||
1257 | static void __clk_set_parent_after(struct clk *clk, struct clk *parent, | ||
1258 | struct clk *old_parent) | ||
1259 | { | ||
1260 | /* | ||
1261 | * Finish the migration of prepare state and undo the changes done | ||
1262 | * for preventing a race with clk_enable(). | ||
1263 | */ | ||
1264 | if (clk->prepare_count) { | ||
1265 | clk_disable(clk); | ||
1266 | clk_disable(old_parent); | ||
1267 | __clk_unprepare(old_parent); | ||
1268 | } | ||
1269 | |||
1270 | /* update debugfs with new clk tree topology */ | ||
1271 | clk_debug_reparent(clk, parent); | ||
1272 | } | ||
1273 | |||
1274 | static int __clk_set_parent(struct clk *clk, struct clk *parent, u8 p_index) | ||
1275 | { | ||
1276 | unsigned long flags; | ||
1277 | int ret = 0; | ||
1278 | struct clk *old_parent; | ||
1279 | |||
1280 | old_parent = __clk_set_parent_before(clk, parent); | ||
1281 | |||
1255 | /* change clock input source */ | 1282 | /* change clock input source */ |
1256 | if (parent && clk->ops->set_parent) | 1283 | if (parent && clk->ops->set_parent) |
1257 | ret = clk->ops->set_parent(clk->hw, p_index); | 1284 | ret = clk->ops->set_parent(clk->hw, p_index); |
@@ -1269,18 +1296,8 @@ static int __clk_set_parent(struct clk *clk, struct clk *parent, u8 p_index) | |||
1269 | return ret; | 1296 | return ret; |
1270 | } | 1297 | } |
1271 | 1298 | ||
1272 | /* | 1299 | __clk_set_parent_after(clk, parent, old_parent); |
1273 | * Finish the migration of prepare state and undo the changes done | ||
1274 | * for preventing a race with clk_enable(). | ||
1275 | */ | ||
1276 | if (clk->prepare_count) { | ||
1277 | clk_disable(clk); | ||
1278 | clk_disable(old_parent); | ||
1279 | __clk_unprepare(old_parent); | ||
1280 | } | ||
1281 | 1300 | ||
1282 | /* update debugfs with new clk tree topology */ | ||
1283 | clk_debug_reparent(clk, parent); | ||
1284 | return 0; | 1301 | return 0; |
1285 | } | 1302 | } |
1286 | 1303 | ||
@@ -1465,17 +1482,32 @@ static void clk_change_rate(struct clk *clk) | |||
1465 | struct clk *child; | 1482 | struct clk *child; |
1466 | unsigned long old_rate; | 1483 | unsigned long old_rate; |
1467 | unsigned long best_parent_rate = 0; | 1484 | unsigned long best_parent_rate = 0; |
1485 | bool skip_set_rate = false; | ||
1486 | struct clk *old_parent; | ||
1468 | 1487 | ||
1469 | old_rate = clk->rate; | 1488 | old_rate = clk->rate; |
1470 | 1489 | ||
1471 | /* set parent */ | 1490 | if (clk->new_parent) |
1472 | if (clk->new_parent && clk->new_parent != clk->parent) | 1491 | best_parent_rate = clk->new_parent->rate; |
1473 | __clk_set_parent(clk, clk->new_parent, clk->new_parent_index); | 1492 | else if (clk->parent) |
1474 | |||
1475 | if (clk->parent) | ||
1476 | best_parent_rate = clk->parent->rate; | 1493 | best_parent_rate = clk->parent->rate; |
1477 | 1494 | ||
1478 | if (clk->ops->set_rate) | 1495 | if (clk->new_parent && clk->new_parent != clk->parent) { |
1496 | old_parent = __clk_set_parent_before(clk, clk->new_parent); | ||
1497 | |||
1498 | if (clk->ops->set_rate_and_parent) { | ||
1499 | skip_set_rate = true; | ||
1500 | clk->ops->set_rate_and_parent(clk->hw, clk->new_rate, | ||
1501 | best_parent_rate, | ||
1502 | clk->new_parent_index); | ||
1503 | } else if (clk->ops->set_parent) { | ||
1504 | clk->ops->set_parent(clk->hw, clk->new_parent_index); | ||
1505 | } | ||
1506 | |||
1507 | __clk_set_parent_after(clk, clk->new_parent, old_parent); | ||
1508 | } | ||
1509 | |||
1510 | if (!skip_set_rate && clk->ops->set_rate) | ||
1479 | clk->ops->set_rate(clk->hw, clk->new_rate, best_parent_rate); | 1511 | clk->ops->set_rate(clk->hw, clk->new_rate, best_parent_rate); |
1480 | 1512 | ||
1481 | if (clk->ops->recalc_rate) | 1513 | if (clk->ops->recalc_rate) |
@@ -1770,6 +1802,14 @@ int __clk_init(struct device *dev, struct clk *clk) | |||
1770 | goto out; | 1802 | goto out; |
1771 | } | 1803 | } |
1772 | 1804 | ||
1805 | if (clk->ops->set_rate_and_parent && | ||
1806 | !(clk->ops->set_parent && clk->ops->set_rate)) { | ||
1807 | pr_warn("%s: %s must implement .set_parent & .set_rate\n", | ||
1808 | __func__, clk->name); | ||
1809 | ret = -EINVAL; | ||
1810 | goto out; | ||
1811 | } | ||
1812 | |||
1773 | /* throw a WARN if any entries in parent_names are NULL */ | 1813 | /* throw a WARN if any entries in parent_names are NULL */ |
1774 | for (i = 0; i < clk->num_parents; i++) | 1814 | for (i = 0; i < clk->num_parents; i++) |
1775 | WARN(!clk->parent_names[i], | 1815 | WARN(!clk->parent_names[i], |
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 5429f5db5037..999b28ba38f7 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h | |||
@@ -116,6 +116,18 @@ struct clk_hw; | |||
116 | * set then clock accuracy will be initialized to parent accuracy | 116 | * set then clock accuracy will be initialized to parent accuracy |
117 | * or 0 (perfect clock) if clock has no parent. | 117 | * or 0 (perfect clock) if clock has no parent. |
118 | * | 118 | * |
119 | * @set_rate_and_parent: Change the rate and the parent of this clock. The | ||
120 | * requested rate is specified by the second argument, which | ||
121 | * should typically be the return of .round_rate call. The | ||
122 | * third argument gives the parent rate which is likely helpful | ||
123 | * for most .set_rate_and_parent implementation. The fourth | ||
124 | * argument gives the parent index. This callback is optional (and | ||
125 | * unnecessary) for clocks with 0 or 1 parents as well as | ||
126 | * for clocks that can tolerate switching the rate and the parent | ||
127 | * separately via calls to .set_parent and .set_rate. | ||
128 | * Returns 0 on success, -EERROR otherwise. | ||
129 | * | ||
130 | * | ||
119 | * The clk_enable/clk_disable and clk_prepare/clk_unprepare pairs allow | 131 | * The clk_enable/clk_disable and clk_prepare/clk_unprepare pairs allow |
120 | * implementations to split any work between atomic (enable) and sleepable | 132 | * implementations to split any work between atomic (enable) and sleepable |
121 | * (prepare) contexts. If enabling a clock requires code that might sleep, | 133 | * (prepare) contexts. If enabling a clock requires code that might sleep, |
@@ -147,6 +159,9 @@ struct clk_ops { | |||
147 | u8 (*get_parent)(struct clk_hw *hw); | 159 | u8 (*get_parent)(struct clk_hw *hw); |
148 | int (*set_rate)(struct clk_hw *hw, unsigned long, | 160 | int (*set_rate)(struct clk_hw *hw, unsigned long, |
149 | unsigned long); | 161 | unsigned long); |
162 | int (*set_rate_and_parent)(struct clk_hw *hw, | ||
163 | unsigned long rate, | ||
164 | unsigned long parent_rate, u8 index); | ||
150 | unsigned long (*recalc_accuracy)(struct clk_hw *hw, | 165 | unsigned long (*recalc_accuracy)(struct clk_hw *hw, |
151 | unsigned long parent_accuracy); | 166 | unsigned long parent_accuracy); |
152 | void (*init)(struct clk_hw *hw); | 167 | void (*init)(struct clk_hw *hw); |