diff options
author | Jonas Gorski <jonas.gorski@gmail.com> | 2019-04-18 07:12:04 -0400 |
---|---|---|
committer | Stephen Boyd <sboyd@kernel.org> | 2019-04-23 13:57:48 -0400 |
commit | 434d69fad63b443d7afc8aa99264359c9b4e2d3a (patch) | |
tree | 5608c21f98cfa92b2ba138498bf48b4015e9e42d | |
parent | 9e98c678c2d6ae3a17cb2de55d17f69dddaa231b (diff) |
clk: divider: add explicit big endian support
Add a clock specific flag to switch register accesses to big endian, to
allow runtime configuration of big endian divider clocks.
Signed-off-by: Jonas Gorski <jonas.gorski@gmail.com>
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
-rw-r--r-- | drivers/clk/clk-divider.c | 24 | ||||
-rw-r--r-- | include/linux/clk-provider.h | 4 |
2 files changed, 24 insertions, 4 deletions
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index e5a17265cfaf..32f93dc6b6d6 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c | |||
@@ -25,6 +25,22 @@ | |||
25 | * parent - fixed parent. No clk_set_parent support | 25 | * parent - fixed parent. No clk_set_parent support |
26 | */ | 26 | */ |
27 | 27 | ||
28 | static inline u32 clk_div_readl(struct clk_divider *divider) | ||
29 | { | ||
30 | if (divider->flags & CLK_DIVIDER_BIG_ENDIAN) | ||
31 | return ioread32be(divider->reg); | ||
32 | |||
33 | return clk_readl(divider->reg); | ||
34 | } | ||
35 | |||
36 | static inline void clk_div_writel(struct clk_divider *divider, u32 val) | ||
37 | { | ||
38 | if (divider->flags & CLK_DIVIDER_BIG_ENDIAN) | ||
39 | iowrite32be(val, divider->reg); | ||
40 | else | ||
41 | clk_writel(val, divider->reg); | ||
42 | } | ||
43 | |||
28 | static unsigned int _get_table_maxdiv(const struct clk_div_table *table, | 44 | static unsigned int _get_table_maxdiv(const struct clk_div_table *table, |
29 | u8 width) | 45 | u8 width) |
30 | { | 46 | { |
@@ -135,7 +151,7 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw, | |||
135 | struct clk_divider *divider = to_clk_divider(hw); | 151 | struct clk_divider *divider = to_clk_divider(hw); |
136 | unsigned int val; | 152 | unsigned int val; |
137 | 153 | ||
138 | val = clk_readl(divider->reg) >> divider->shift; | 154 | val = clk_div_readl(divider) >> divider->shift; |
139 | val &= clk_div_mask(divider->width); | 155 | val &= clk_div_mask(divider->width); |
140 | 156 | ||
141 | return divider_recalc_rate(hw, parent_rate, val, divider->table, | 157 | return divider_recalc_rate(hw, parent_rate, val, divider->table, |
@@ -370,7 +386,7 @@ static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, | |||
370 | if (divider->flags & CLK_DIVIDER_READ_ONLY) { | 386 | if (divider->flags & CLK_DIVIDER_READ_ONLY) { |
371 | u32 val; | 387 | u32 val; |
372 | 388 | ||
373 | val = clk_readl(divider->reg) >> divider->shift; | 389 | val = clk_div_readl(divider) >> divider->shift; |
374 | val &= clk_div_mask(divider->width); | 390 | val &= clk_div_mask(divider->width); |
375 | 391 | ||
376 | return divider_ro_round_rate(hw, rate, prate, divider->table, | 392 | return divider_ro_round_rate(hw, rate, prate, divider->table, |
@@ -420,11 +436,11 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, | |||
420 | if (divider->flags & CLK_DIVIDER_HIWORD_MASK) { | 436 | if (divider->flags & CLK_DIVIDER_HIWORD_MASK) { |
421 | val = clk_div_mask(divider->width) << (divider->shift + 16); | 437 | val = clk_div_mask(divider->width) << (divider->shift + 16); |
422 | } else { | 438 | } else { |
423 | val = clk_readl(divider->reg); | 439 | val = clk_div_readl(divider); |
424 | val &= ~(clk_div_mask(divider->width) << divider->shift); | 440 | val &= ~(clk_div_mask(divider->width) << divider->shift); |
425 | } | 441 | } |
426 | val |= (u32)value << divider->shift; | 442 | val |= (u32)value << divider->shift; |
427 | clk_writel(val, divider->reg); | 443 | clk_div_writel(divider, val); |
428 | 444 | ||
429 | if (divider->lock) | 445 | if (divider->lock) |
430 | spin_unlock_irqrestore(divider->lock, flags); | 446 | spin_unlock_irqrestore(divider->lock, flags); |
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index b7cf80a71293..f0abdfbe3d60 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h | |||
@@ -417,6 +417,9 @@ struct clk_div_table { | |||
417 | * CLK_DIVIDER_MAX_AT_ZERO - For dividers which are like CLK_DIVIDER_ONE_BASED | 417 | * CLK_DIVIDER_MAX_AT_ZERO - For dividers which are like CLK_DIVIDER_ONE_BASED |
418 | * except when the value read from the register is zero, the divisor is | 418 | * except when the value read from the register is zero, the divisor is |
419 | * 2^width of the field. | 419 | * 2^width of the field. |
420 | * CLK_DIVIDER_BIG_ENDIAN - By default little endian register accesses are used | ||
421 | * for the divider register. Setting this flag makes the register accesses | ||
422 | * big endian. | ||
420 | */ | 423 | */ |
421 | struct clk_divider { | 424 | struct clk_divider { |
422 | struct clk_hw hw; | 425 | struct clk_hw hw; |
@@ -438,6 +441,7 @@ struct clk_divider { | |||
438 | #define CLK_DIVIDER_ROUND_CLOSEST BIT(4) | 441 | #define CLK_DIVIDER_ROUND_CLOSEST BIT(4) |
439 | #define CLK_DIVIDER_READ_ONLY BIT(5) | 442 | #define CLK_DIVIDER_READ_ONLY BIT(5) |
440 | #define CLK_DIVIDER_MAX_AT_ZERO BIT(6) | 443 | #define CLK_DIVIDER_MAX_AT_ZERO BIT(6) |
444 | #define CLK_DIVIDER_BIG_ENDIAN BIT(7) | ||
441 | 445 | ||
442 | extern const struct clk_ops clk_divider_ops; | 446 | extern const struct clk_ops clk_divider_ops; |
443 | extern const struct clk_ops clk_divider_ro_ops; | 447 | extern const struct clk_ops clk_divider_ro_ops; |