diff mbox

[v2,18/24] i2c: mpc: OF clock lookup for MPC512x

Message ID 1374178858-8683-4-git-send-email-gsi@denx.de (mailing list archive)
State New, archived
Headers show

Commit Message

Gerhard Sittig July 18, 2013, 8:20 p.m. UTC
make the MPC I2C driver prepare and enable the peripheral clock
('per' for register access) in the MPC512x setup routine,
make this clock setup non-fatal to allow for a migration period,
remove the pre-enabling hack in the platform's clock driver

Signed-off-by: Gerhard Sittig <gsi@denx.de>
---
 arch/powerpc/platforms/512x/clock-commonclk.c |    1 -
 drivers/i2c/busses/i2c-mpc.c                  |    9 +++++++++
 2 files changed, 9 insertions(+), 1 deletion(-)

Comments

Russell King - ARM Linux July 18, 2013, 8:33 p.m. UTC | #1
On Thu, Jul 18, 2013 at 10:20:52PM +0200, Gerhard Sittig wrote:
> +	/* enable clock for the I2C peripheral (non fatal) */
> +	clk = of_clk_get_by_name(node, "per");
> +	if (!IS_ERR(clk)) {
> +		clk_prepare_enable(clk);
> +		clk_put(clk);
> +	}
> +

This kind of hacked up approach to the clk API is exactly the thing I
really don't like seeing.  I don't know what it is... is the clk API
somehow difficult to use or what's the problem with doing stuff correctly?

1. Get the clock in your probe function.
2. Prepare it at the appropriate time.
3. Enable it appropriately.  (or if you want to combine 2 and 3, use
   clk_prepare_enable().)
4. Ensure that enables/disables and prepares/unprepares are appropriately
   balanced.
5. 'put' the clock in your remove function.

Certainly do not get-enable-put a clock.  You're supposed to hold on to
the clock all the time that you're actually using it.

Final point - if you want to make it non-fatal, don't play games like:

	clk = clk_get(whatever);
	if (IS_ERR(clk))
		clk = NULL;

	...
	if (clk)
		clk_prepare(clk);

Do this instead:

	clk = clk_get(whatever);
	...

	if (!IS_ERR(clk))
		clk_prepare(clk);
etc.

(And on this subject, I'm considering whether to make a change to the
clk API where clk_prepare() and clk_enable() return zero when passed
an error pointer - this means drivers with optional clocks don't have
to burden themselves with these kinds of checks.)
Gerhard Sittig July 19, 2013, 8:42 a.m. UTC | #2
On Thu, Jul 18, 2013 at 21:33 +0100, Russell King - ARM Linux wrote:
> 
> On Thu, Jul 18, 2013 at 10:20:52PM +0200, Gerhard Sittig wrote:
> > +	/* enable clock for the I2C peripheral (non fatal) */
> > +	clk = of_clk_get_by_name(node, "per");
> > +	if (!IS_ERR(clk)) {
> > +		clk_prepare_enable(clk);
> > +		clk_put(clk);
> > +	}
> > +
> 
> This kind of hacked up approach to the clk API is exactly the thing I
> really don't like seeing.  I don't know what it is... is the clk API
> somehow difficult to use or what's the problem with doing stuff correctly?
> 
> 1. Get the clock in your probe function.
> 2. Prepare it at the appropriate time.
> 3. Enable it appropriately.  (or if you want to combine 2 and 3, use
>    clk_prepare_enable().)
> 4. Ensure that enables/disables and prepares/unprepares are appropriately
>    balanced.
> 5. 'put' the clock in your remove function.
> 
> Certainly do not get-enable-put a clock.  You're supposed to hold on to
> the clock all the time that you're actually using it.

Russel, thank you for the feedback!  I agree that your outline of
steps to take is simple and should not be a problem to do.

I noticed that I kept looking at the wrong spot in the driver,
hooked up to some setup routine which lacks a counter part.  You
made me re-visit the drivers and find better locations to hook up
to (probe and remove).  Part of my sloppiness with immediate put
after enable was caused by put being a NOP at the moment, and the
assumption that clocks without references but in the enabled
state won't go away.  But I saw your recent message as well about
how clocks shall get reference counted and keep their provider's
module loaded.

I've queued an update to the I2C, ethernet, and PCI drivers,
which addresses your concerns.  I2C and ethernet clock handling
will become correctly balanced, while PCI won't since the
existing driver already lacks a remove() routine.  These changes
will be part of v3 of the series.

Mark, Greg, v2 of the series already addresses the above concerns
for the serial communication with the PSC hardware (UART and
SPI).  See how 01/24 and 02/24 became much more complex than in
v1, yet should result in appropriate clock handling in these
drivers.

In the very minute I wanted to send out v3, I received feedback
on the CAN driver manipulation from Marc.  Apparently it suffers
from the same problem (my blindness to locate the best spot for
resource release), but CAN shall be the last driver in the series
which is not acceptable yet.


> Final point - if you want to make it non-fatal, don't play games like:
> 
> 	clk = clk_get(whatever);
> 	if (IS_ERR(clk))
> 		clk = NULL;
> 
> 	...
> 	if (clk)
> 		clk_prepare(clk);
> 
> Do this instead:
> 
> 	clk = clk_get(whatever);
> 	...
> 
> 	if (!IS_ERR(clk))
> 		clk_prepare(clk);
> etc.

You saw this in the ethernet driver, right?  This "interesting"
style of "normalization to NULL" in the setup path was meant to
simplify the cleanup path, but that point has become obsolete by
now.  Your example doesn't reflect that 'clk' was a more complex
to access member in the driver's private data.

It seems that doing the setup in steps with a local variable, to
only store the reference when all steps were successful, cleans
up the release code paths.

Immediately putting the clock and not having stored the reference
when enable failed is one more instruction before jumping to the
bailout label, but eliminates the pain of tracking get and enable
separately, and needing two labels for disable and put (you
cannot disable a clock that wasn't enabled).

As mentioned, both the I2C driver you responded to as well as the
ethernet driver you reference here got adjusted.  v3 will get
sent when I could address the remaining CAN driver issue.


> (And on this subject, I'm considering whether to make a change to the
> clk API where clk_prepare() and clk_enable() return zero when passed
> an error pointer - this means drivers with optional clocks don't have
> to burden themselves with these kinds of checks.)


virtually yours
Gerhard Sittig
diff mbox

Patch

diff --git a/arch/powerpc/platforms/512x/clock-commonclk.c b/arch/powerpc/platforms/512x/clock-commonclk.c
index b8963b7..49c52bc 100644
--- a/arch/powerpc/platforms/512x/clock-commonclk.c
+++ b/arch/powerpc/platforms/512x/clock-commonclk.c
@@ -692,7 +692,6 @@  static void mpc512x_clk_setup_clock_tree(int busfreq)
 	/* some are not yet acquired by their respective drivers */
 	clk_prepare_enable(clks[MPC512x_CLK_PSC3_MCLK]);/* serial console */
 	clk_prepare_enable(clks[MPC512x_CLK_FEC]);	/* network, NFS */
-	clk_prepare_enable(clks[MPC512x_CLK_I2C]);
 	/*
 	 * some have their individual clock subtree with separate clock
 	 * items and their individual enable counters, yet share a
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index 7607dc0..13d6822 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -21,6 +21,7 @@ 
 #include <linux/of_i2c.h>
 #include <linux/slab.h>
 
+#include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/fsl_devices.h>
 #include <linux/i2c.h>
@@ -264,11 +265,19 @@  static void mpc_i2c_setup_512x(struct device_node *node,
 					 struct mpc_i2c *i2c,
 					 u32 clock, u32 prescaler)
 {
+	struct clk *clk;
 	struct device_node *node_ctrl;
 	void __iomem *ctrl;
 	const u32 *pval;
 	u32 idx;
 
+	/* enable clock for the I2C peripheral (non fatal) */
+	clk = of_clk_get_by_name(node, "per");
+	if (!IS_ERR(clk)) {
+		clk_prepare_enable(clk);
+		clk_put(clk);
+	}
+
 	/* Enable I2C interrupts for mpc5121 */
 	node_ctrl = of_find_compatible_node(NULL, NULL,
 					    "fsl,mpc5121-i2c-ctrl");