aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGerhard Sittig <gsi@denx.de>2013-08-23 07:09:03 -0400
committerMarc Kleine-Budde <mkl@pengutronix.de>2013-08-29 16:49:35 -0400
commit1149108e2fbf98899447d4567901bf07825ee576 (patch)
tree640ce11fc641ae4e70c37293e5433ea4fd66632c
parent3a09b12e0c2ef26a0e2230606a6159d3038a1572 (diff)
can: mscan: improve clock API use
the .get_clock() callback is run from probe() and might allocate resources, introduce a .put_clock() callback that is run from remove() to undo any allocation activities prepare and enable the clocks in open(), disable and unprepare the clocks in close() if clocks were acquired during probe(), to not assume knowledge about which activities are done in probe() and remove() use devm_get_clk() to lookup the SYS and REF clocks, to have the clocks put upon device shutdown store pointers to data structures upon successful allocation already instead of deferral until complete setup, such that subroutines in the setup sequence may access those data structures as well to track their resource acquisition since clock allocation remains optional, the release callback as well as the enable/disable calls in open/close are optional as well Cc: linux-can@vger.kernel.org Cc: netdev@vger.kernel.org Signed-off-by: Gerhard Sittig <gsi@denx.de> Signed-off-by: Anatolij Gustschin <agust@denx.de> Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
-rw-r--r--drivers/net/can/mscan/mpc5xxx_can.c18
-rw-r--r--drivers/net/can/mscan/mscan.c25
-rw-r--r--drivers/net/can/mscan/mscan.h3
3 files changed, 39 insertions, 7 deletions
diff --git a/drivers/net/can/mscan/mpc5xxx_can.c b/drivers/net/can/mscan/mpc5xxx_can.c
index bc422ba3d13b..e59b3a392af6 100644
--- a/drivers/net/can/mscan/mpc5xxx_can.c
+++ b/drivers/net/can/mscan/mpc5xxx_can.c
@@ -40,6 +40,7 @@ struct mpc5xxx_can_data {
40 unsigned int type; 40 unsigned int type;
41 u32 (*get_clock)(struct platform_device *ofdev, const char *clock_name, 41 u32 (*get_clock)(struct platform_device *ofdev, const char *clock_name,
42 int *mscan_clksrc); 42 int *mscan_clksrc);
43 void (*put_clock)(struct platform_device *ofdev);
43}; 44};
44 45
45#ifdef CONFIG_PPC_MPC52xx 46#ifdef CONFIG_PPC_MPC52xx
@@ -180,7 +181,7 @@ static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
180 clockdiv = 1; 181 clockdiv = 1;
181 182
182 if (!clock_name || !strcmp(clock_name, "sys")) { 183 if (!clock_name || !strcmp(clock_name, "sys")) {
183 sys_clk = clk_get(&ofdev->dev, "sys_clk"); 184 sys_clk = devm_clk_get(&ofdev->dev, "sys_clk");
184 if (IS_ERR(sys_clk)) { 185 if (IS_ERR(sys_clk)) {
185 dev_err(&ofdev->dev, "couldn't get sys_clk\n"); 186 dev_err(&ofdev->dev, "couldn't get sys_clk\n");
186 goto exit_unmap; 187 goto exit_unmap;
@@ -203,7 +204,7 @@ static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
203 } 204 }
204 205
205 if (clocksrc < 0) { 206 if (clocksrc < 0) {
206 ref_clk = clk_get(&ofdev->dev, "ref_clk"); 207 ref_clk = devm_clk_get(&ofdev->dev, "ref_clk");
207 if (IS_ERR(ref_clk)) { 208 if (IS_ERR(ref_clk)) {
208 dev_err(&ofdev->dev, "couldn't get ref_clk\n"); 209 dev_err(&ofdev->dev, "couldn't get ref_clk\n");
209 goto exit_unmap; 210 goto exit_unmap;
@@ -280,6 +281,8 @@ static int mpc5xxx_can_probe(struct platform_device *ofdev)
280 dev = alloc_mscandev(); 281 dev = alloc_mscandev();
281 if (!dev) 282 if (!dev)
282 goto exit_dispose_irq; 283 goto exit_dispose_irq;
284 platform_set_drvdata(ofdev, dev);
285 SET_NETDEV_DEV(dev, &ofdev->dev);
283 286
284 priv = netdev_priv(dev); 287 priv = netdev_priv(dev);
285 priv->reg_base = base; 288 priv->reg_base = base;
@@ -296,8 +299,6 @@ static int mpc5xxx_can_probe(struct platform_device *ofdev)
296 goto exit_free_mscan; 299 goto exit_free_mscan;
297 } 300 }
298 301
299 SET_NETDEV_DEV(dev, &ofdev->dev);
300
301 err = register_mscandev(dev, mscan_clksrc); 302 err = register_mscandev(dev, mscan_clksrc);
302 if (err) { 303 if (err) {
303 dev_err(&ofdev->dev, "registering %s failed (err=%d)\n", 304 dev_err(&ofdev->dev, "registering %s failed (err=%d)\n",
@@ -305,8 +306,6 @@ static int mpc5xxx_can_probe(struct platform_device *ofdev)
305 goto exit_free_mscan; 306 goto exit_free_mscan;
306 } 307 }
307 308
308 platform_set_drvdata(ofdev, dev);
309
310 dev_info(&ofdev->dev, "MSCAN at 0x%p, irq %d, clock %d Hz\n", 309 dev_info(&ofdev->dev, "MSCAN at 0x%p, irq %d, clock %d Hz\n",
311 priv->reg_base, dev->irq, priv->can.clock.freq); 310 priv->reg_base, dev->irq, priv->can.clock.freq);
312 311
@@ -324,10 +323,17 @@ exit_unmap_mem:
324 323
325static int mpc5xxx_can_remove(struct platform_device *ofdev) 324static int mpc5xxx_can_remove(struct platform_device *ofdev)
326{ 325{
326 const struct of_device_id *match;
327 const struct mpc5xxx_can_data *data;
327 struct net_device *dev = platform_get_drvdata(ofdev); 328 struct net_device *dev = platform_get_drvdata(ofdev);
328 struct mscan_priv *priv = netdev_priv(dev); 329 struct mscan_priv *priv = netdev_priv(dev);
329 330
331 match = of_match_device(mpc5xxx_can_table, &ofdev->dev);
332 data = match ? match->data : NULL;
333
330 unregister_mscandev(dev); 334 unregister_mscandev(dev);
335 if (data && data->put_clock)
336 data->put_clock(ofdev);
331 iounmap(priv->reg_base); 337 iounmap(priv->reg_base);
332 irq_dispose_mapping(dev->irq); 338 irq_dispose_mapping(dev->irq);
333 free_candev(dev); 339 free_candev(dev);
diff --git a/drivers/net/can/mscan/mscan.c b/drivers/net/can/mscan/mscan.c
index e6b40954e204..a955ec8c4b97 100644
--- a/drivers/net/can/mscan/mscan.c
+++ b/drivers/net/can/mscan/mscan.c
@@ -573,10 +573,21 @@ static int mscan_open(struct net_device *dev)
573 struct mscan_priv *priv = netdev_priv(dev); 573 struct mscan_priv *priv = netdev_priv(dev);
574 struct mscan_regs __iomem *regs = priv->reg_base; 574 struct mscan_regs __iomem *regs = priv->reg_base;
575 575
576 if (priv->clk_ipg) {
577 ret = clk_prepare_enable(priv->clk_ipg);
578 if (ret)
579 goto exit_retcode;
580 }
581 if (priv->clk_can) {
582 ret = clk_prepare_enable(priv->clk_can);
583 if (ret)
584 goto exit_dis_ipg_clock;
585 }
586
576 /* common open */ 587 /* common open */
577 ret = open_candev(dev); 588 ret = open_candev(dev);
578 if (ret) 589 if (ret)
579 return ret; 590 goto exit_dis_can_clock;
580 591
581 napi_enable(&priv->napi); 592 napi_enable(&priv->napi);
582 593
@@ -604,6 +615,13 @@ exit_free_irq:
604exit_napi_disable: 615exit_napi_disable:
605 napi_disable(&priv->napi); 616 napi_disable(&priv->napi);
606 close_candev(dev); 617 close_candev(dev);
618exit_dis_can_clock:
619 if (priv->clk_can)
620 clk_disable_unprepare(priv->clk_can);
621exit_dis_ipg_clock:
622 if (priv->clk_ipg)
623 clk_disable_unprepare(priv->clk_ipg);
624exit_retcode:
607 return ret; 625 return ret;
608} 626}
609 627
@@ -621,6 +639,11 @@ static int mscan_close(struct net_device *dev)
621 close_candev(dev); 639 close_candev(dev);
622 free_irq(dev->irq, dev); 640 free_irq(dev->irq, dev);
623 641
642 if (priv->clk_can)
643 clk_disable_unprepare(priv->clk_can);
644 if (priv->clk_ipg)
645 clk_disable_unprepare(priv->clk_ipg);
646
624 return 0; 647 return 0;
625} 648}
626 649
diff --git a/drivers/net/can/mscan/mscan.h b/drivers/net/can/mscan/mscan.h
index af2ed8baf0a3..9c24d60a23b1 100644
--- a/drivers/net/can/mscan/mscan.h
+++ b/drivers/net/can/mscan/mscan.h
@@ -21,6 +21,7 @@
21#ifndef __MSCAN_H__ 21#ifndef __MSCAN_H__
22#define __MSCAN_H__ 22#define __MSCAN_H__
23 23
24#include <linux/clk.h>
24#include <linux/types.h> 25#include <linux/types.h>
25 26
26/* MSCAN control register 0 (CANCTL0) bits */ 27/* MSCAN control register 0 (CANCTL0) bits */
@@ -283,6 +284,8 @@ struct mscan_priv {
283 unsigned int type; /* MSCAN type variants */ 284 unsigned int type; /* MSCAN type variants */
284 unsigned long flags; 285 unsigned long flags;
285 void __iomem *reg_base; /* ioremap'ed address to registers */ 286 void __iomem *reg_base; /* ioremap'ed address to registers */
287 struct clk *clk_ipg; /* clock for registers */
288 struct clk *clk_can; /* clock for bitrates */
286 u8 shadow_statflg; 289 u8 shadow_statflg;
287 u8 shadow_canrier; 290 u8 shadow_canrier;
288 u8 cur_pri; 291 u8 cur_pri;