aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter De Schrijver <pdeschrijver@nvidia.com>2013-03-22 08:07:53 -0400
committerMike Turquette <mturquette@linaro.org>2013-03-22 18:18:18 -0400
commitce4f3313b05c836c21a91ac89f87dccf84ce9561 (patch)
treeab0f642d4ad1cc37b5a08ca0db5ac34f83ca84a8
parent5fda6858a49c2d8706adcc05f083b64af172d3eb (diff)
clk: add table lookup to mux
Add a table lookup feature to the mux clock. Also allow arbitrary masks instead of the width. This will be used by some clocks on Tegra114. Also adapt the tegra periph clk because it uses struct clk_mux directly. Signed-off-by: Peter De Schrijver <pdeschrijver@nvidia.com> Tested-by: Stephen Warren <swarren@nvidia.com> Signed-off-by: Mike Turquette <mturquette@linaro.org>
-rw-r--r--drivers/clk/clk-mux.c50
-rw-r--r--drivers/clk/tegra/clk.h27
-rw-r--r--include/linux/clk-private.h2
-rw-r--r--include/linux/clk-provider.h9
4 files changed, 67 insertions, 21 deletions
diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c
index 508c032edce4..25b1734560d0 100644
--- a/drivers/clk/clk-mux.c
+++ b/drivers/clk/clk-mux.c
@@ -32,6 +32,7 @@
32static u8 clk_mux_get_parent(struct clk_hw *hw) 32static u8 clk_mux_get_parent(struct clk_hw *hw)
33{ 33{
34 struct clk_mux *mux = to_clk_mux(hw); 34 struct clk_mux *mux = to_clk_mux(hw);
35 int num_parents = __clk_get_num_parents(hw->clk);
35 u32 val; 36 u32 val;
36 37
37 /* 38 /*
@@ -42,7 +43,16 @@ static u8 clk_mux_get_parent(struct clk_hw *hw)
42 * val = 0x4 really means "bit 2, index starts at bit 0" 43 * val = 0x4 really means "bit 2, index starts at bit 0"
43 */ 44 */
44 val = readl(mux->reg) >> mux->shift; 45 val = readl(mux->reg) >> mux->shift;
45 val &= (1 << mux->width) - 1; 46 val &= mux->mask;
47
48 if (mux->table) {
49 int i;
50
51 for (i = 0; i < num_parents; i++)
52 if (mux->table[i] == val)
53 return i;
54 return -EINVAL;
55 }
46 56
47 if (val && (mux->flags & CLK_MUX_INDEX_BIT)) 57 if (val && (mux->flags & CLK_MUX_INDEX_BIT))
48 val = ffs(val) - 1; 58 val = ffs(val) - 1;
@@ -50,7 +60,7 @@ static u8 clk_mux_get_parent(struct clk_hw *hw)
50 if (val && (mux->flags & CLK_MUX_INDEX_ONE)) 60 if (val && (mux->flags & CLK_MUX_INDEX_ONE))
51 val--; 61 val--;
52 62
53 if (val >= __clk_get_num_parents(hw->clk)) 63 if (val >= num_parents)
54 return -EINVAL; 64 return -EINVAL;
55 65
56 return val; 66 return val;
@@ -62,17 +72,22 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
62 u32 val; 72 u32 val;
63 unsigned long flags = 0; 73 unsigned long flags = 0;
64 74
65 if (mux->flags & CLK_MUX_INDEX_BIT) 75 if (mux->table)
66 index = (1 << ffs(index)); 76 index = mux->table[index];
67 77
68 if (mux->flags & CLK_MUX_INDEX_ONE) 78 else {
69 index++; 79 if (mux->flags & CLK_MUX_INDEX_BIT)
80 index = (1 << ffs(index));
81
82 if (mux->flags & CLK_MUX_INDEX_ONE)
83 index++;
84 }
70 85
71 if (mux->lock) 86 if (mux->lock)
72 spin_lock_irqsave(mux->lock, flags); 87 spin_lock_irqsave(mux->lock, flags);
73 88
74 val = readl(mux->reg); 89 val = readl(mux->reg);
75 val &= ~(((1 << mux->width) - 1) << mux->shift); 90 val &= ~(mux->mask << mux->shift);
76 val |= index << mux->shift; 91 val |= index << mux->shift;
77 writel(val, mux->reg); 92 writel(val, mux->reg);
78 93
@@ -88,10 +103,10 @@ const struct clk_ops clk_mux_ops = {
88}; 103};
89EXPORT_SYMBOL_GPL(clk_mux_ops); 104EXPORT_SYMBOL_GPL(clk_mux_ops);
90 105
91struct clk *clk_register_mux(struct device *dev, const char *name, 106struct clk *clk_register_mux_table(struct device *dev, const char *name,
92 const char **parent_names, u8 num_parents, unsigned long flags, 107 const char **parent_names, u8 num_parents, unsigned long flags,
93 void __iomem *reg, u8 shift, u8 width, 108 void __iomem *reg, u8 shift, u32 mask,
94 u8 clk_mux_flags, spinlock_t *lock) 109 u8 clk_mux_flags, u32 *table, spinlock_t *lock)
95{ 110{
96 struct clk_mux *mux; 111 struct clk_mux *mux;
97 struct clk *clk; 112 struct clk *clk;
@@ -113,9 +128,10 @@ struct clk *clk_register_mux(struct device *dev, const char *name,
113 /* struct clk_mux assignments */ 128 /* struct clk_mux assignments */
114 mux->reg = reg; 129 mux->reg = reg;
115 mux->shift = shift; 130 mux->shift = shift;
116 mux->width = width; 131 mux->mask = mask;
117 mux->flags = clk_mux_flags; 132 mux->flags = clk_mux_flags;
118 mux->lock = lock; 133 mux->lock = lock;
134 mux->table = table;
119 mux->hw.init = &init; 135 mux->hw.init = &init;
120 136
121 clk = clk_register(dev, &mux->hw); 137 clk = clk_register(dev, &mux->hw);
@@ -125,3 +141,15 @@ struct clk *clk_register_mux(struct device *dev, const char *name,
125 141
126 return clk; 142 return clk;
127} 143}
144
145struct clk *clk_register_mux(struct device *dev, const char *name,
146 const char **parent_names, u8 num_parents, unsigned long flags,
147 void __iomem *reg, u8 shift, u8 width,
148 u8 clk_mux_flags, spinlock_t *lock)
149{
150 u32 mask = BIT(width) - 1;
151
152 return clk_register_mux_table(dev, name, parent_names, num_parents,
153 flags, reg, shift, mask, clk_mux_flags,
154 NULL, lock);
155}
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index 0744731c6229..a09d7dcaf183 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -355,15 +355,16 @@ struct clk *tegra_clk_register_periph_nodiv(const char *name,
355 struct tegra_clk_periph *periph, void __iomem *clk_base, 355 struct tegra_clk_periph *periph, void __iomem *clk_base,
356 u32 offset); 356 u32 offset);
357 357
358#define TEGRA_CLK_PERIPH(_mux_shift, _mux_width, _mux_flags, \ 358#define TEGRA_CLK_PERIPH(_mux_shift, _mux_mask, _mux_flags, \
359 _div_shift, _div_width, _div_frac_width, \ 359 _div_shift, _div_width, _div_frac_width, \
360 _div_flags, _clk_num, _enb_refcnt, _regs, \ 360 _div_flags, _clk_num, _enb_refcnt, _regs, \
361 _gate_flags) \ 361 _gate_flags, _table) \
362 { \ 362 { \
363 .mux = { \ 363 .mux = { \
364 .flags = _mux_flags, \ 364 .flags = _mux_flags, \
365 .shift = _mux_shift, \ 365 .shift = _mux_shift, \
366 .width = _mux_width, \ 366 .mask = _mux_mask, \
367 .table = _table, \
367 }, \ 368 }, \
368 .divider = { \ 369 .divider = { \
369 .flags = _div_flags, \ 370 .flags = _div_flags, \
@@ -393,26 +394,36 @@ struct tegra_periph_init_data {
393 const char *dev_id; 394 const char *dev_id;
394}; 395};
395 396
396#define TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parent_names, _offset, \ 397#define TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parent_names, _offset,\
397 _mux_shift, _mux_width, _mux_flags, _div_shift, \ 398 _mux_shift, _mux_mask, _mux_flags, _div_shift, \
398 _div_width, _div_frac_width, _div_flags, _regs, \ 399 _div_width, _div_frac_width, _div_flags, _regs, \
399 _clk_num, _enb_refcnt, _gate_flags, _clk_id) \ 400 _clk_num, _enb_refcnt, _gate_flags, _clk_id, _table) \
400 { \ 401 { \
401 .name = _name, \ 402 .name = _name, \
402 .clk_id = _clk_id, \ 403 .clk_id = _clk_id, \
403 .parent_names = _parent_names, \ 404 .parent_names = _parent_names, \
404 .num_parents = ARRAY_SIZE(_parent_names), \ 405 .num_parents = ARRAY_SIZE(_parent_names), \
405 .periph = TEGRA_CLK_PERIPH(_mux_shift, _mux_width, \ 406 .periph = TEGRA_CLK_PERIPH(_mux_shift, _mux_mask, \
406 _mux_flags, _div_shift, \ 407 _mux_flags, _div_shift, \
407 _div_width, _div_frac_width, \ 408 _div_width, _div_frac_width, \
408 _div_flags, _clk_num, \ 409 _div_flags, _clk_num, \
409 _enb_refcnt, _regs, \ 410 _enb_refcnt, _regs, \
410 _gate_flags), \ 411 _gate_flags, _table), \
411 .offset = _offset, \ 412 .offset = _offset, \
412 .con_id = _con_id, \ 413 .con_id = _con_id, \
413 .dev_id = _dev_id, \ 414 .dev_id = _dev_id, \
414 } 415 }
415 416
417#define TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parent_names, _offset,\
418 _mux_shift, _mux_width, _mux_flags, _div_shift, \
419 _div_width, _div_frac_width, _div_flags, _regs, \
420 _clk_num, _enb_refcnt, _gate_flags, _clk_id) \
421 TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parent_names, _offset,\
422 _mux_shift, BIT(_mux_width) - 1, _mux_flags, \
423 _div_shift, _div_width, _div_frac_width, _div_flags, \
424 _regs, _clk_num, _enb_refcnt, _gate_flags, _clk_id,\
425 NULL)
426
416/** 427/**
417 * struct clk_super_mux - super clock 428 * struct clk_super_mux - super clock
418 * 429 *
diff --git a/include/linux/clk-private.h b/include/linux/clk-private.h
index 9c7f5807824b..dd7adff76e81 100644
--- a/include/linux/clk-private.h
+++ b/include/linux/clk-private.h
@@ -152,7 +152,7 @@ struct clk {
152 }, \ 152 }, \
153 .reg = _reg, \ 153 .reg = _reg, \
154 .shift = _shift, \ 154 .shift = _shift, \
155 .width = _width, \ 155 .mask = BIT(_width) - 1, \
156 .flags = _mux_flags, \ 156 .flags = _mux_flags, \
157 .lock = _lock, \ 157 .lock = _lock, \
158 }; \ 158 }; \
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 56e6cc12c796..63ba3b740794 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -297,8 +297,9 @@ struct clk *clk_register_divider_table(struct device *dev, const char *name,
297struct clk_mux { 297struct clk_mux {
298 struct clk_hw hw; 298 struct clk_hw hw;
299 void __iomem *reg; 299 void __iomem *reg;
300 u32 *table;
301 u32 mask;
300 u8 shift; 302 u8 shift;
301 u8 width;
302 u8 flags; 303 u8 flags;
303 spinlock_t *lock; 304 spinlock_t *lock;
304}; 305};
@@ -307,11 +308,17 @@ struct clk_mux {
307#define CLK_MUX_INDEX_BIT BIT(1) 308#define CLK_MUX_INDEX_BIT BIT(1)
308 309
309extern const struct clk_ops clk_mux_ops; 310extern const struct clk_ops clk_mux_ops;
311
310struct clk *clk_register_mux(struct device *dev, const char *name, 312struct clk *clk_register_mux(struct device *dev, const char *name,
311 const char **parent_names, u8 num_parents, unsigned long flags, 313 const char **parent_names, u8 num_parents, unsigned long flags,
312 void __iomem *reg, u8 shift, u8 width, 314 void __iomem *reg, u8 shift, u8 width,
313 u8 clk_mux_flags, spinlock_t *lock); 315 u8 clk_mux_flags, spinlock_t *lock);
314 316
317struct clk *clk_register_mux_table(struct device *dev, const char *name,
318 const char **parent_names, u8 num_parents, unsigned long flags,
319 void __iomem *reg, u8 shift, u32 mask,
320 u8 clk_mux_flags, u32 *table, spinlock_t *lock);
321
315/** 322/**
316 * struct clk_fixed_factor - fixed multiplier and divider clock 323 * struct clk_fixed_factor - fixed multiplier and divider clock
317 * 324 *