From: "Heiko Stübner" <heiko-4mtYJXux2i+zQB+pC5nmwQ@public.gmane.org>
To: "linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org"
<linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org>
Cc: Mike Turquette
<mturquette-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>,
Seungwon Jeon <tgih.jun-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>,
linux-mmc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
"linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org"
<linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>,
Rob Herring <rob.herring-bsGFqQB8/DxBDgjK7y7TUQ@public.gmane.org>,
Jaehoon Chung
<jh80.chung-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>,
John Stultz <john.stultz-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>,
Grant Likely
<grant.likely-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>,
Russell King <linux-lFZ/pmaqli7XmaaqVzeoHQ@public.gmane.org>,
Thomas Gleixner <tglx-hfZtesqFncYOwBW4kG4KsQ@public.gmane.org>,
Chris Ball <cjb-2X9k7bc8m7Mdnm+yROfE0A@public.gmane.org>,
devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ@public.gmane.org
Subject: [PATCH 03/10] clk: flag to use upper half of the register as change indicator
Date: Mon, 3 Jun 2013 00:57:15 +0200 [thread overview]
Message-ID: <201306030057.15989.heiko@sntech.de> (raw)
In-Reply-To: <201306030055.15413.heiko-4mtYJXux2i+zQB+pC5nmwQ@public.gmane.org>
There exist platforms, namely at least all Rockchip Cortex-A9 based ones,
that don't use the paradigm of reading-changing-writing the register contents,
but instead only write the changes to the register with a mask that indicates
the changed bits.
This patch adds flags and code to support the case where the lower 16 bit of
hold the information and the upper 16 bit are used as mask to indicate the
written changes.
As hardware-specific flags should not be added to the common clk flags, the
flags are added to gate, mux and divider clocks individually.
Signed-off-by: Heiko Stuebner <heiko-4mtYJXux2i+zQB+pC5nmwQ@public.gmane.org>
---
drivers/clk/clk-divider.c | 15 +++++++++++++--
drivers/clk/clk-gate.c | 24 ++++++++++++++++++------
drivers/clk/clk-mux.c | 15 +++++++++++++--
include/linux/clk-provider.h | 16 ++++++++++++++++
4 files changed, 60 insertions(+), 10 deletions(-)
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index 6d96741..e37c48a 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -217,8 +217,12 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
if (divider->lock)
spin_lock_irqsave(divider->lock, flags);
- val = readl(divider->reg);
- val &= ~(div_mask(divider) << divider->shift);
+ if (divider->flags & CLK_DIVIDER_MASK_UPPER_HALF) {
+ val = div_mask(divider) << (divider->shift + 16);
+ } else {
+ val = readl(divider->reg);
+ val &= ~(div_mask(divider) << divider->shift);
+ }
val |= value << divider->shift;
writel(val, divider->reg);
@@ -245,6 +249,13 @@ static struct clk *_register_divider(struct device *dev, const char *name,
struct clk *clk;
struct clk_init_data init;
+ if ((clk_divider_flags & CLK_DIVIDER_MASK_UPPER_HALF) &&
+ (shift + width > 15)) {
+ pr_err("%s: shift %d + width %d invalid\n", __func__,
+ shift, width);
+ return ERR_PTR(-EINVAL);
+ }
+
/* allocate the divider */
div = kzalloc(sizeof(struct clk_divider), GFP_KERNEL);
if (!div) {
diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c
index 15114fe..e553fa7 100644
--- a/drivers/clk/clk-gate.c
+++ b/drivers/clk/clk-gate.c
@@ -53,12 +53,19 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
if (gate->lock)
spin_lock_irqsave(gate->lock, flags);
- reg = readl(gate->reg);
-
- if (set)
- reg |= BIT(gate->bit_idx);
- else
- reg &= ~BIT(gate->bit_idx);
+ if (gate->flags & CLK_GATE_MASK_UPPER_HALF) {
+ reg = BIT(gate->bit_idx + 16);
+
+ if (set)
+ reg |= BIT(gate->bit_idx);
+ } else {
+ reg = readl(gate->reg);
+
+ if (set)
+ reg |= BIT(gate->bit_idx);
+ else
+ reg &= ~BIT(gate->bit_idx);
+ }
writel(reg, gate->reg);
@@ -121,6 +128,11 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
struct clk *clk;
struct clk_init_data init;
+ if ((clk_gate_flags & CLK_GATE_MASK_UPPER_HALF) && bit_idx > 15) {
+ pr_err("%s: bit_idx %d invalid\n", __func__, bit_idx);
+ return ERR_PTR(-EINVAL);
+ }
+
/* allocate the gate */
gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL);
if (!gate) {
diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c
index 25b1734..fce26f5 100644
--- a/drivers/clk/clk-mux.c
+++ b/drivers/clk/clk-mux.c
@@ -86,8 +86,12 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
if (mux->lock)
spin_lock_irqsave(mux->lock, flags);
- val = readl(mux->reg);
- val &= ~(mux->mask << mux->shift);
+ if (mux->flags & CLK_MUX_MASK_UPPER_HALF) {
+ val = mux->mask << (mux->shift + 16);
+ } else {
+ val = readl(mux->reg);
+ val &= ~(mux->mask << mux->shift);
+ }
val |= index << mux->shift;
writel(val, mux->reg);
@@ -112,6 +116,13 @@ struct clk *clk_register_mux_table(struct device *dev, const char *name,
struct clk *clk;
struct clk_init_data init;
+ if (!mask || ((clk_mux_flags & CLK_MUX_MASK_UPPER_HALF) &&
+ (__fls(mask << shift) > 15))) {
+ pr_err("%s: shift %d + mask %d invalid\n", __func__,
+ shift, mask);
+ return ERR_PTR(-EINVAL);
+ }
+
/* allocate the mux */
mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL);
if (!mux) {
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 265f384..420a187 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -210,6 +210,11 @@ void of_fixed_clk_setup(struct device_node *np);
* CLK_GATE_SET_TO_DISABLE - by default this clock sets the bit at bit_idx to
* enable the clock. Setting this flag does the opposite: setting the bit
* disable the clock and clearing it enables the clock
+ * CLK_GATE_MASK_UPPER_HALF - this clock only uses the lower 16 bit of the
+ * register to hold the gate bits, while using the upper 16 bit to
+ * indicate the bits that get changed during a write. So gating the
+ * clock in bit 2 would write BIT(18) | BIT(2) to the register, while
+ * ungating this clock would write only BIT(18) to the register.
*/
struct clk_gate {
struct clk_hw hw;
@@ -220,6 +225,7 @@ struct clk_gate {
};
#define CLK_GATE_SET_TO_DISABLE BIT(0)
+#define CLK_GATE_MASK_UPPER_HALF BIT(1)
extern const struct clk_ops clk_gate_ops;
struct clk *clk_register_gate(struct device *dev, const char *name,
@@ -257,6 +263,11 @@ struct clk_div_table {
* Some hardware implementations gracefully handle this case and allow a
* zero divisor by not modifying their input clock
* (divide by one / bypass).
+ * CLK_DIVIDER_MASK_UPPER_HALF - this clock only uses the lower 16 bit of the
+ * register to hold the divider bits, while using the upper 16 bit to
+ * indicate the bits that get changed during a write. So for a clock with
+ * shift 0 and width 2, setting the divider to 2 would result in a write
+ * of (3 << 16) | (2 << 0).
*/
struct clk_divider {
struct clk_hw hw;
@@ -271,6 +282,7 @@ struct clk_divider {
#define CLK_DIVIDER_ONE_BASED BIT(0)
#define CLK_DIVIDER_POWER_OF_TWO BIT(1)
#define CLK_DIVIDER_ALLOW_ZERO BIT(2)
+#define CLK_DIVIDER_MASK_UPPER_HALF BIT(3)
extern const struct clk_ops clk_divider_ops;
struct clk *clk_register_divider(struct device *dev, const char *name,
@@ -299,6 +311,9 @@ struct clk *clk_register_divider_table(struct device *dev, const char *name,
* Flags:
* CLK_MUX_INDEX_ONE - register index starts at 1, not 0
* CLK_MUX_INDEX_BIT - register index is a single bit (power of two)
+ * CLK_MUX_MASK_UPPER_HALF - this clock only uses the lower 16 bit of the
+ * register to hold the mux bits, while using the upper 16 bit to
+ * indicate the bits that get changed during a write.
*/
struct clk_mux {
struct clk_hw hw;
@@ -312,6 +327,7 @@ struct clk_mux {
#define CLK_MUX_INDEX_ONE BIT(0)
#define CLK_MUX_INDEX_BIT BIT(1)
+#define CLK_MUX_MASK_UPPER_HALF BIT(3)
extern const struct clk_ops clk_mux_ops;
--
1.7.2.3
next prev parent reply other threads:[~2013-06-02 22:57 UTC|newest]
Thread overview: 43+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-06-02 22:55 arm: add basic support for Rockchip Cortex-A9 SoCs Heiko Stübner
[not found] ` <201306030055.15413.heiko-4mtYJXux2i+zQB+pC5nmwQ@public.gmane.org>
2013-06-02 22:56 ` [PATCH 01/10] clocksource: dw_apb_timer_of: use the clocksource as sched clock if necessary Heiko Stübner
2013-06-04 6:34 ` Linus Walleij
2013-06-04 8:29 ` Heiko Stübner
2013-06-04 9:43 ` Linus Walleij
2013-06-02 22:56 ` [PATCH 02/10] clocksource: dw_apb_timer_of: add clock-handling Heiko Stübner
2013-06-03 3:22 ` Baruch Siach
2013-06-03 7:51 ` Heiko Stübner
2013-06-02 22:57 ` Heiko Stübner [this message]
2013-06-02 22:57 ` [PATCH 04/10] clk: divider: add flag to limit possible dividers to even numbers Heiko Stübner
2013-06-02 22:58 ` [PATCH 05/10] mmc: dw_mmc-pltfm: remove static from dw_mci_pltfm_remove Heiko Stübner
2013-06-04 3:59 ` Jaehoon Chung
[not found] ` <201306030058.27184.heiko-4mtYJXux2i+zQB+pC5nmwQ@public.gmane.org>
2013-06-05 14:00 ` Seungwon Jeon
2013-06-02 22:59 ` [PATCH 06/10] mmc: dw_mmc-pltfm: add Rockchip variant Heiko Stübner
2013-06-04 4:06 ` Jaehoon Chung
2013-06-04 8:43 ` Heiko Stübner
[not found] ` <201306030059.03783.heiko-4mtYJXux2i+zQB+pC5nmwQ@public.gmane.org>
2013-06-05 14:00 ` Seungwon Jeon
2013-06-05 14:11 ` Heiko Stübner
2013-06-06 20:01 ` Andy Shevchenko
2013-06-02 22:59 ` [PATCH 07/10] pinctrl: add pinctrl driver for Rockchip SoCs Heiko Stübner
2013-06-04 7:08 ` Linus Walleij
2013-06-04 12:05 ` Heiko Stübner
2013-06-05 7:01 ` Linus Walleij
2013-06-05 17:18 ` Stephen Warren
[not found] ` <51AF72F9.3060307-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
2013-06-05 18:50 ` Heiko Stübner
2013-06-02 23:00 ` [PATCH 08/10] clk: add basic Rockchip rk3066a clock support Heiko Stübner
2013-06-03 3:27 ` Olof Johansson
[not found] ` <20130603032711.GA3379-O5ziIzlqnXUVNXGz7ipsyg@public.gmane.org>
2013-06-03 7:52 ` Heiko Stübner
2013-06-02 23:01 ` [PATCH 09/10] arm: add debug uarts for rockchip rk29xx and rk3xxx series Heiko Stübner
2013-06-03 2:08 ` Arnd Bergmann
2013-06-03 7:54 ` Heiko Stübner
2013-06-02 23:02 ` [PATCH 10/10] arm: add basic support for Rockchip RK3066a boards Heiko Stübner
2013-06-03 2:15 ` Arnd Bergmann
2013-06-03 8:23 ` Heiko Stübner
[not found] ` <201306031023.49364.heiko-4mtYJXux2i+zQB+pC5nmwQ@public.gmane.org>
2013-06-03 9:22 ` Arnd Bergmann
2013-06-03 9:46 ` Heiko Stübner
2013-06-03 10:26 ` Arnd Bergmann
2013-06-03 12:15 ` [RFC] dw_apb_timer_of: use clocksource_of_init Heiko Stübner
2013-06-03 12:27 ` Rob Herring
2013-06-03 13:20 ` Arnd Bergmann
2013-06-05 7:11 ` [PATCH 10/10] arm: add basic support for Rockchip RK3066a boards Thomas Petazzoni
2013-06-05 21:45 ` Maxime Ripard
2013-06-03 2:07 ` arm: add basic support for Rockchip Cortex-A9 SoCs Arnd Bergmann
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=201306030057.15989.heiko@sntech.de \
--to=heiko-4mtyjxux2i+zqb+pc5nmwq@public.gmane.org \
--cc=cjb-2X9k7bc8m7Mdnm+yROfE0A@public.gmane.org \
--cc=devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ@public.gmane.org \
--cc=grant.likely-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org \
--cc=jh80.chung-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org \
--cc=john.stultz-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org \
--cc=linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org \
--cc=linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
--cc=linux-lFZ/pmaqli7XmaaqVzeoHQ@public.gmane.org \
--cc=linux-mmc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
--cc=mturquette-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org \
--cc=rob.herring-bsGFqQB8/DxBDgjK7y7TUQ@public.gmane.org \
--cc=tgih.jun-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org \
--cc=tglx-hfZtesqFncYOwBW4kG4KsQ@public.gmane.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox