diff mbox

[PATCHv9,01/43] clk: Add support for regmap register read/write

Message ID 1382716658-6964-2-git-send-email-t-kristo@ti.com (mailing list archive)
State New, archived
Headers show

Commit Message

Tero Kristo Oct. 25, 2013, 3:56 p.m. UTC
Previously, only direct register read/write was supported. Now a per-clock
regmap can be provided for same purpose, which allows the clock drivers
to access clock registers behind e.g. I2C bus.

Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
 drivers/clk/clk-divider.c    |    6 +++---
 drivers/clk/clk-gate.c       |    6 +++---
 drivers/clk/clk-mux.c        |    6 +++---
 include/linux/clk-provider.h |   23 +++++++++++++++++++----
 4 files changed, 28 insertions(+), 13 deletions(-)

Comments

Nishanth Menon Oct. 31, 2013, 2:03 p.m. UTC | #1
On 10/25/2013 10:56 AM, Tero Kristo wrote:
[...]
> diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
> index 7e59253..63ff78c 100644
> --- a/include/linux/clk-provider.h
> +++ b/include/linux/clk-provider.h

[...]
> -static inline u32 clk_readl(u32 __iomem *reg)
> +static inline u32 clk_readl(u32 __iomem *reg, struct regmap *regmap)
>  {
> -	return readl(reg);
> +	u32 val;
> +
> +	if (regmap)
> +		regmap_read(regmap, (u32)reg, &val);
> +	else
> +		val = readl(reg);
> +	return val;
>  }
>  
> -static inline void clk_writel(u32 val, u32 __iomem *reg)
> +static inline void clk_writel(u32 val, u32 __iomem *reg, struct regmap *regmap)
>  {
> -	writel(val, reg);
> +	if (regmap)
> +		regmap_write(regmap, (u32)reg, val);
> +	else
> +		writel(val, reg);
>  }
>  
>  #endif /* CONFIG_COMMON_CLK */
> 

Might it not be better to introduce regmap variants?
static inline void clk_regmap_writel(u32 val, u32 reg, struct regmap
*regmap)
and corresponding readl? that allows cleaner readability for clk
drivers that use regmap and those that dont.

regmap can also return error value that could also be handled as a result.
Tero Kristo Oct. 31, 2013, 2:40 p.m. UTC | #2
On 10/31/2013 04:03 PM, Nishanth Menon wrote:
> On 10/25/2013 10:56 AM, Tero Kristo wrote:
> [...]
>> diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
>> index 7e59253..63ff78c 100644
>> --- a/include/linux/clk-provider.h
>> +++ b/include/linux/clk-provider.h
>
> [...]
>> -static inline u32 clk_readl(u32 __iomem *reg)
>> +static inline u32 clk_readl(u32 __iomem *reg, struct regmap *regmap)
>>   {
>> -	return readl(reg);
>> +	u32 val;
>> +
>> +	if (regmap)
>> +		regmap_read(regmap, (u32)reg, &val);
>> +	else
>> +		val = readl(reg);
>> +	return val;
>>   }
>>
>> -static inline void clk_writel(u32 val, u32 __iomem *reg)
>> +static inline void clk_writel(u32 val, u32 __iomem *reg, struct regmap *regmap)
>>   {
>> -	writel(val, reg);
>> +	if (regmap)
>> +		regmap_write(regmap, (u32)reg, val);
>> +	else
>> +		writel(val, reg);
>>   }
>>
>>   #endif /* CONFIG_COMMON_CLK */
>>
>
> Might it not be better to introduce regmap variants?
> static inline void clk_regmap_writel(u32 val, u32 reg, struct regmap
> *regmap)
> and corresponding readl? that allows cleaner readability for clk
> drivers that use regmap and those that dont.

Well, doing that will introduce a lot of redundant code, as the checks 
for the presence of regmap must be copied all over the place. With this 
patch, all the generic clock drivers support internally both regmap or 
non-regmap register accesses.

> regmap can also return error value that could also be handled as a result.

True, however if the regmap fails for the clock code, not sure what we 
can do but panic. If this code is expanded, it is probably better to not 
inline it anymore.

-Tero
Nishanth Menon Oct. 31, 2013, 3:46 p.m. UTC | #3
On 10/31/2013 09:40 AM, Tero Kristo wrote:
> On 10/31/2013 04:03 PM, Nishanth Menon wrote:
>> On 10/25/2013 10:56 AM, Tero Kristo wrote:
>> [...]
>>> diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
>>> index 7e59253..63ff78c 100644
>>> --- a/include/linux/clk-provider.h
>>> +++ b/include/linux/clk-provider.h
>>
>> [...]
>>> -static inline u32 clk_readl(u32 __iomem *reg)
>>> +static inline u32 clk_readl(u32 __iomem *reg, struct regmap *regmap)
>>>   {
>>> -	return readl(reg);
>>> +	u32 val;
>>> +
>>> +	if (regmap)
>>> +		regmap_read(regmap, (u32)reg, &val);
>>> +	else
>>> +		val = readl(reg);
>>> +	return val;
>>>   }
>>>
>>> -static inline void clk_writel(u32 val, u32 __iomem *reg)
>>> +static inline void clk_writel(u32 val, u32 __iomem *reg, struct regmap *regmap)
>>>   {
>>> -	writel(val, reg);
>>> +	if (regmap)
>>> +		regmap_write(regmap, (u32)reg, val);
>>> +	else
>>> +		writel(val, reg);
>>>   }
>>>
>>>   #endif /* CONFIG_COMMON_CLK */
>>>
>>
>> Might it not be better to introduce regmap variants?
>> static inline void clk_regmap_writel(u32 val, u32 reg, struct regmap
>> *regmap)
>> and corresponding readl? that allows cleaner readability for clk
>> drivers that use regmap and those that dont.
> 
> Well, doing that will introduce a lot of redundant code, as the checks 
> for the presence of regmap must be copied all over the place. With this 
> patch, all the generic clock drivers support internally both regmap or 
> non-regmap register accesses.
> 

using function pointers might be an appropriate solution. in general a
low level reg access api that uses two different approaches sounds a
little.. umm.. fishy..

>> regmap can also return error value that could also be handled as a result.
> 
> True, however if the regmap fails for the clock code, not sure what we 
> can do but panic. If this code is expanded, it is probably better to not 
> inline it anymore.
> 
let the compiler deal with that decision. regmap operation fail should
be percollated back to initiator of the request. in some cases that
will be ir-recoverable, but on other cases panic might be the right
answer - at the low level we are in no position to make that distinction.
Tero Kristo Nov. 1, 2013, 8:57 a.m. UTC | #4
On 10/31/2013 05:46 PM, Nishanth Menon wrote:
> On 10/31/2013 09:40 AM, Tero Kristo wrote:
>> On 10/31/2013 04:03 PM, Nishanth Menon wrote:
>>> On 10/25/2013 10:56 AM, Tero Kristo wrote:
>>> [...]
>>>> diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
>>>> index 7e59253..63ff78c 100644
>>>> --- a/include/linux/clk-provider.h
>>>> +++ b/include/linux/clk-provider.h
>>>
>>> [...]
>>>> -static inline u32 clk_readl(u32 __iomem *reg)
>>>> +static inline u32 clk_readl(u32 __iomem *reg, struct regmap *regmap)
>>>>    {
>>>> -	return readl(reg);
>>>> +	u32 val;
>>>> +
>>>> +	if (regmap)
>>>> +		regmap_read(regmap, (u32)reg, &val);
>>>> +	else
>>>> +		val = readl(reg);
>>>> +	return val;
>>>>    }
>>>>
>>>> -static inline void clk_writel(u32 val, u32 __iomem *reg)
>>>> +static inline void clk_writel(u32 val, u32 __iomem *reg, struct regmap *regmap)
>>>>    {
>>>> -	writel(val, reg);
>>>> +	if (regmap)
>>>> +		regmap_write(regmap, (u32)reg, val);
>>>> +	else
>>>> +		writel(val, reg);
>>>>    }
>>>>
>>>>    #endif /* CONFIG_COMMON_CLK */
>>>>
>>>
>>> Might it not be better to introduce regmap variants?
>>> static inline void clk_regmap_writel(u32 val, u32 reg, struct regmap
>>> *regmap)
>>> and corresponding readl? that allows cleaner readability for clk
>>> drivers that use regmap and those that dont.
>>
>> Well, doing that will introduce a lot of redundant code, as the checks
>> for the presence of regmap must be copied all over the place. With this
>> patch, all the generic clock drivers support internally both regmap or
>> non-regmap register accesses.
>>
>
> using function pointers might be an appropriate solution. in general a
> low level reg access api that uses two different approaches sounds a
> little.. umm.. fishy..

Initial work I did for v9 had clk_reg_ops struct in place which pretty 
much did this, however Mike recommended looking at the regmap so I did. 
I could put the reg_ops struct back and just have it use internally 
regmap if that would be better, but I guess we need comment from Mike 
how he wants this to be done.

We could have:

struct clk_reg_ops {
	int (*clk_readl)(u32 addr, u32 *val);
	int (*clk_writel)(u32 addr, u32 val);
};

struct clk_foo {
	...
	void __iomem *reg;
	struct clk_reg_ops *regops;
};

>
>>> regmap can also return error value that could also be handled as a result.
>>
>> True, however if the regmap fails for the clock code, not sure what we
>> can do but panic. If this code is expanded, it is probably better to not
>> inline it anymore.
>>
> let the compiler deal with that decision. regmap operation fail should
> be percollated back to initiator of the request. in some cases that
> will be ir-recoverable, but on other cases panic might be the right
> answer - at the low level we are in no position to make that distinction.

Currently, none of the clock drivers handle failures for regmap 
operations, I can of course add some sort of support for this given what 
we do with above point and what the API for the register accesses ends 
up like.

-Tero
Tomasz Figa Nov. 2, 2013, 1:26 p.m. UTC | #5
Hi Tero,

On Friday 25 of October 2013 18:56:55 Tero Kristo wrote:
> Previously, only direct register read/write was supported. Now a
> per-clock regmap can be provided for same purpose, which allows the
> clock drivers to access clock registers behind e.g. I2C bus.
> 
> Signed-off-by: Tero Kristo <t-kristo@ti.com>
> ---
>  drivers/clk/clk-divider.c    |    6 +++---
>  drivers/clk/clk-gate.c       |    6 +++---
>  drivers/clk/clk-mux.c        |    6 +++---
>  include/linux/clk-provider.h |   23 +++++++++++++++++++----
>  4 files changed, 28 insertions(+), 13 deletions(-)

The idea itself sounds not bad, but patch description fails to specify 
what is the need for this. I mean, if you know that this will have some 
actual users, it is nice to specify them.

Also IMHO the variant with clk_reg_ops (but with regmap used) would look a 
bit better in terms of readability and extensibility, but I'm leaving this 
completely to Mike's decision.

(OR maybe you could migrate this fully to regmap, which can do MMIO 
accesses as well, without the need of having separate code paths for both 
in clock code?)

Best regards,
Tomasz
Gerhard Sittig Nov. 5, 2013, 9:43 p.m. UTC | #6
On Thu, Oct 31, 2013 at 16:40 +0200, Tero Kristo wrote:
> 
> On 10/31/2013 04:03 PM, Nishanth Menon wrote:
> >On 10/25/2013 10:56 AM, Tero Kristo wrote:
> >[...]
> >>diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
> >>index 7e59253..63ff78c 100644
> >>--- a/include/linux/clk-provider.h
> >>+++ b/include/linux/clk-provider.h
> >
> >[...]
> >>-static inline u32 clk_readl(u32 __iomem *reg)
> >>+static inline u32 clk_readl(u32 __iomem *reg, struct regmap *regmap)
> >>  {
> >>-	return readl(reg);
> >>+	u32 val;
> >>+
> >>+	if (regmap)
> >>+		regmap_read(regmap, (u32)reg, &val);
> >>+	else
> >>+		val = readl(reg);
> >>+	return val;
> >>  }
> >>
> >>-static inline void clk_writel(u32 val, u32 __iomem *reg)
> >>+static inline void clk_writel(u32 val, u32 __iomem *reg, struct regmap *regmap)
> >>  {
> >>-	writel(val, reg);
> >>+	if (regmap)
> >>+		regmap_write(regmap, (u32)reg, val);
> >>+	else
> >>+		writel(val, reg);
> >>  }
> >>
> >>  #endif /* CONFIG_COMMON_CLK */
> >>
> >
> >Might it not be better to introduce regmap variants?
> >static inline void clk_regmap_writel(u32 val, u32 reg, struct regmap
> >*regmap)
> >and corresponding readl? that allows cleaner readability for clk
> >drivers that use regmap and those that dont.
> 
> Well, doing that will introduce a lot of redundant code, as the
> checks for the presence of regmap must be copied all over the place.
> With this patch, all the generic clock drivers support internally
> both regmap or non-regmap register accesses.

Please keep in mind that the "identity" of clk_readl() and
readl() only applies in the current source code (ARM only use of
common CCF primitives), while patches are pending (currently
under review and receiving further improvement) which introduce
several alternative implementations of clk_readl() depending on
the platform.  Making all of them duplicate the "regmap vs direct
register access" branch would be as bad.  Keeping one set of
clk_readl() and clk_writel() routines and adding #ifdefs around
the direct register access would be rather ugly, and I understand
that preprocessor ifdef counts should get reduced instead of
introduced.


virtually yours
Gerhard Sittig
Tero Kristo Nov. 6, 2013, 10:54 a.m. UTC | #7
On 11/05/2013 11:43 PM, Gerhard Sittig wrote:
> On Thu, Oct 31, 2013 at 16:40 +0200, Tero Kristo wrote:
>>
>> On 10/31/2013 04:03 PM, Nishanth Menon wrote:
>>> On 10/25/2013 10:56 AM, Tero Kristo wrote:
>>> [...]
>>>> diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
>>>> index 7e59253..63ff78c 100644
>>>> --- a/include/linux/clk-provider.h
>>>> +++ b/include/linux/clk-provider.h
>>>
>>> [...]
>>>> -static inline u32 clk_readl(u32 __iomem *reg)
>>>> +static inline u32 clk_readl(u32 __iomem *reg, struct regmap *regmap)
>>>>   {
>>>> -	return readl(reg);
>>>> +	u32 val;
>>>> +
>>>> +	if (regmap)
>>>> +		regmap_read(regmap, (u32)reg, &val);
>>>> +	else
>>>> +		val = readl(reg);
>>>> +	return val;
>>>>   }
>>>>
>>>> -static inline void clk_writel(u32 val, u32 __iomem *reg)
>>>> +static inline void clk_writel(u32 val, u32 __iomem *reg, struct regmap *regmap)
>>>>   {
>>>> -	writel(val, reg);
>>>> +	if (regmap)
>>>> +		regmap_write(regmap, (u32)reg, val);
>>>> +	else
>>>> +		writel(val, reg);
>>>>   }
>>>>
>>>>   #endif /* CONFIG_COMMON_CLK */
>>>>
>>>
>>> Might it not be better to introduce regmap variants?
>>> static inline void clk_regmap_writel(u32 val, u32 reg, struct regmap
>>> *regmap)
>>> and corresponding readl? that allows cleaner readability for clk
>>> drivers that use regmap and those that dont.
>>
>> Well, doing that will introduce a lot of redundant code, as the
>> checks for the presence of regmap must be copied all over the place.
>> With this patch, all the generic clock drivers support internally
>> both regmap or non-regmap register accesses.
>
> Please keep in mind that the "identity" of clk_readl() and
> readl() only applies in the current source code (ARM only use of
> common CCF primitives), while patches are pending (currently
> under review and receiving further improvement) which introduce
> several alternative implementations of clk_readl() depending on
> the platform.  Making all of them duplicate the "regmap vs direct
> register access" branch would be as bad.  Keeping one set of
> clk_readl() and clk_writel() routines and adding #ifdefs around
> the direct register access would be rather ugly, and I understand
> that preprocessor ifdef counts should get reduced instead of
> introduced.

So, it might be better to provide platform / or clock specific 
clk_reg_ops or something, so we can cover all the possible cases easily.

The requirement from TI SoC point of view is that:

1) need to be able to specify custom register read/write ops
2) need to be able to provide an index parameter to the read/write ops
3) need to be able to provide a register offset to the read/write ops

This could be done in following way for example:

clk_readl / clk_writel would be accessed through a single platform 
specific struct which provides function pointers to both.

The content of 'reg' provided to the clk_readl / clk_writel would be 
internally interpreted as a

struct omap_clk_reg_internal {
	u16 offset;
	u16 index;
};

... the index part would be used to select the appropriate regmap to 
use, and TI SoC:s would be using 3...4 regmaps for actually accessing 
the physical registers themselves.

-Tero

>
>
> virtually yours
> Gerhard Sittig
>
diff mbox

Patch

diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index 8d3009e..9c17b1a 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -104,7 +104,7 @@  static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
 	struct clk_divider *divider = to_clk_divider(hw);
 	unsigned int div, val;
 
-	val = clk_readl(divider->reg) >> divider->shift;
+	val = clk_readl(divider->reg, divider->regmap) >> divider->shift;
 	val &= div_mask(divider);
 
 	div = _get_div(divider, val);
@@ -230,11 +230,11 @@  static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
 	if (divider->flags & CLK_DIVIDER_HIWORD_MASK) {
 		val = div_mask(divider) << (divider->shift + 16);
 	} else {
-		val = clk_readl(divider->reg);
+		val = clk_readl(divider->reg, divider->regmap);
 		val &= ~(div_mask(divider) << divider->shift);
 	}
 	val |= value << divider->shift;
-	clk_writel(val, divider->reg);
+	clk_writel(val, divider->reg, divider->regmap);
 
 	if (divider->lock)
 		spin_unlock_irqrestore(divider->lock, flags);
diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c
index 4a58c55..3c7f686 100644
--- a/drivers/clk/clk-gate.c
+++ b/drivers/clk/clk-gate.c
@@ -58,7 +58,7 @@  static void clk_gate_endisable(struct clk_hw *hw, int enable)
 		if (set)
 			reg |= BIT(gate->bit_idx);
 	} else {
-		reg = clk_readl(gate->reg);
+		reg = clk_readl(gate->reg, gate->regmap);
 
 		if (set)
 			reg |= BIT(gate->bit_idx);
@@ -66,7 +66,7 @@  static void clk_gate_endisable(struct clk_hw *hw, int enable)
 			reg &= ~BIT(gate->bit_idx);
 	}
 
-	clk_writel(reg, gate->reg);
+	clk_writel(reg, gate->reg, gate->regmap);
 
 	if (gate->lock)
 		spin_unlock_irqrestore(gate->lock, flags);
@@ -89,7 +89,7 @@  static int clk_gate_is_enabled(struct clk_hw *hw)
 	u32 reg;
 	struct clk_gate *gate = to_clk_gate(hw);
 
-	reg = clk_readl(gate->reg);
+	reg = clk_readl(gate->reg, gate->regmap);
 
 	/* if a set bit disables this clk, flip it before masking */
 	if (gate->flags & CLK_GATE_SET_TO_DISABLE)
diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c
index 4f96ff3..68eb8c2 100644
--- a/drivers/clk/clk-mux.c
+++ b/drivers/clk/clk-mux.c
@@ -42,7 +42,7 @@  static u8 clk_mux_get_parent(struct clk_hw *hw)
 	 * OTOH, pmd_trace_clk_mux_ck uses a separate bit for each clock, so
 	 * val = 0x4 really means "bit 2, index starts at bit 0"
 	 */
-	val = clk_readl(mux->reg) >> mux->shift;
+	val = clk_readl(mux->reg, mux->regmap) >> mux->shift;
 	val &= mux->mask;
 
 	if (mux->table) {
@@ -89,11 +89,11 @@  static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
 	if (mux->flags & CLK_MUX_HIWORD_MASK) {
 		val = mux->mask << (mux->shift + 16);
 	} else {
-		val = clk_readl(mux->reg);
+		val = clk_readl(mux->reg, mux->regmap);
 		val &= ~(mux->mask << mux->shift);
 	}
 	val |= index << mux->shift;
-	clk_writel(val, mux->reg);
+	clk_writel(val, mux->reg, mux->regmap);
 
 	if (mux->lock)
 		spin_unlock_irqrestore(mux->lock, flags);
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 7e59253..63ff78c 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -13,6 +13,7 @@ 
 
 #include <linux/clk.h>
 #include <linux/io.h>
+#include <linux/regmap.h>
 
 #ifdef CONFIG_COMMON_CLK
 
@@ -209,6 +210,7 @@  void of_fixed_clk_setup(struct device_node *np);
  *
  * @hw:		handle between common and hardware-specific interfaces
  * @reg:	register controlling gate
+ * @regmap:	regmap for accessing the gate register (if any)
  * @bit_idx:	single bit controlling gate
  * @flags:	hardware-specific flags
  * @lock:	register lock
@@ -227,6 +229,7 @@  void of_fixed_clk_setup(struct device_node *np);
 struct clk_gate {
 	struct clk_hw hw;
 	void __iomem	*reg;
+	struct regmap	*regmap;
 	u8		bit_idx;
 	u8		flags;
 	spinlock_t	*lock;
@@ -251,6 +254,7 @@  struct clk_div_table {
  *
  * @hw:		handle between common and hardware-specific interfaces
  * @reg:	register containing the divider
+ * @regmap:	regmap for accessing the divider register (if any)
  * @shift:	shift to the divider bit field
  * @width:	width of the divider bit field
  * @table:	array of value/divider pairs, last entry should have div = 0
@@ -279,6 +283,7 @@  struct clk_div_table {
 struct clk_divider {
 	struct clk_hw	hw;
 	void __iomem	*reg;
+	struct regmap	*regmap;
 	u8		shift;
 	u8		width;
 	u8		flags;
@@ -326,6 +331,7 @@  struct clk *clk_register_divider_table(struct device *dev, const char *name,
 struct clk_mux {
 	struct clk_hw	hw;
 	void __iomem	*reg;
+	struct regmap	*regmap;
 	u32		*table;
 	u32		mask;
 	u8		shift;
@@ -512,14 +518,23 @@  static inline const char *of_clk_get_parent_name(struct device_node *np,
  * for improved portability across platforms
  */
 
-static inline u32 clk_readl(u32 __iomem *reg)
+static inline u32 clk_readl(u32 __iomem *reg, struct regmap *regmap)
 {
-	return readl(reg);
+	u32 val;
+
+	if (regmap)
+		regmap_read(regmap, (u32)reg, &val);
+	else
+		val = readl(reg);
+	return val;
 }
 
-static inline void clk_writel(u32 val, u32 __iomem *reg)
+static inline void clk_writel(u32 val, u32 __iomem *reg, struct regmap *regmap)
 {
-	writel(val, reg);
+	if (regmap)
+		regmap_write(regmap, (u32)reg, val);
+	else
+		writel(val, reg);
 }
 
 #endif /* CONFIG_COMMON_CLK */