On 08/06/2013 10:43 PM, Gerhard Sittig wrote:
> 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
> 
> Signed-off-by: Gerhard Sittig <g...@denx.de>
> ---
>  drivers/net/can/mscan/mpc5xxx_can.c |   18 ++++++++++++------
>  drivers/net/can/mscan/mscan.c       |   27 ++++++++++++++++++++++++++-
>  drivers/net/can/mscan/mscan.h       |    3 +++
>  3 files changed, 41 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/net/can/mscan/mpc5xxx_can.c 
> b/drivers/net/can/mscan/mpc5xxx_can.c
> index bc422ba..e59b3a3 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 {
>       unsigned int type;
>       u32 (*get_clock)(struct platform_device *ofdev, const char *clock_name,
>                        int *mscan_clksrc);
> +     void (*put_clock)(struct platform_device *ofdev);
>  };
>  
>  #ifdef CONFIG_PPC_MPC52xx
> @@ -180,7 +181,7 @@ static u32 mpc512x_can_get_clock(struct platform_device 
> *ofdev,
>                       clockdiv = 1;
>  
>               if (!clock_name || !strcmp(clock_name, "sys")) {
> -                     sys_clk = clk_get(&ofdev->dev, "sys_clk");
> +                     sys_clk = devm_clk_get(&ofdev->dev, "sys_clk");
>                       if (IS_ERR(sys_clk)) {
>                               dev_err(&ofdev->dev, "couldn't get sys_clk\n");
>                               goto exit_unmap;
> @@ -203,7 +204,7 @@ static u32 mpc512x_can_get_clock(struct platform_device 
> *ofdev,
>               }
>  
>               if (clocksrc < 0) {
> -                     ref_clk = clk_get(&ofdev->dev, "ref_clk");
> +                     ref_clk = devm_clk_get(&ofdev->dev, "ref_clk");
>                       if (IS_ERR(ref_clk)) {
>                               dev_err(&ofdev->dev, "couldn't get ref_clk\n");
>                               goto exit_unmap;
> @@ -280,6 +281,8 @@ static int mpc5xxx_can_probe(struct platform_device 
> *ofdev)
>       dev = alloc_mscandev();
>       if (!dev)
>               goto exit_dispose_irq;
> +     platform_set_drvdata(ofdev, dev);
> +     SET_NETDEV_DEV(dev, &ofdev->dev);
>  
>       priv = netdev_priv(dev);
>       priv->reg_base = base;
> @@ -296,8 +299,6 @@ static int mpc5xxx_can_probe(struct platform_device 
> *ofdev)
>               goto exit_free_mscan;
>       }
>  
> -     SET_NETDEV_DEV(dev, &ofdev->dev);
> -
>       err = register_mscandev(dev, mscan_clksrc);
>       if (err) {
>               dev_err(&ofdev->dev, "registering %s failed (err=%d)\n",
> @@ -305,8 +306,6 @@ static int mpc5xxx_can_probe(struct platform_device 
> *ofdev)
>               goto exit_free_mscan;
>       }
>  
> -     platform_set_drvdata(ofdev, dev);
> -
>       dev_info(&ofdev->dev, "MSCAN at 0x%p, irq %d, clock %d Hz\n",
>                priv->reg_base, dev->irq, priv->can.clock.freq);
>  
> @@ -324,10 +323,17 @@ exit_unmap_mem:
>  
>  static int mpc5xxx_can_remove(struct platform_device *ofdev)
>  {
> +     const struct of_device_id *match;
> +     const struct mpc5xxx_can_data *data;
>       struct net_device *dev = platform_get_drvdata(ofdev);
>       struct mscan_priv *priv = netdev_priv(dev);
>  
> +     match = of_match_device(mpc5xxx_can_table, &ofdev->dev);
> +     data = match ? match->data : NULL;
> +
>       unregister_mscandev(dev);
> +     if (data && data->put_clock)
> +             data->put_clock(ofdev);
>       iounmap(priv->reg_base);
>       irq_dispose_mapping(dev->irq);
>       free_candev(dev);
> diff --git a/drivers/net/can/mscan/mscan.c b/drivers/net/can/mscan/mscan.c
> index e6b4095..4f998f5 100644
> --- a/drivers/net/can/mscan/mscan.c
> +++ b/drivers/net/can/mscan/mscan.c
> @@ -573,10 +573,24 @@ static int mscan_open(struct net_device *dev)
>       struct mscan_priv *priv = netdev_priv(dev);
>       struct mscan_regs __iomem *regs = priv->reg_base;
>  
> +     if (priv->clk_ipg) {
> +             ret = clk_prepare_enable(priv->clk_ipg);
> +             if (ret)
> +                     goto exit_retcode;
> +     }
> +     if (priv->clk_can) {
> +             ret = clk_prepare_enable(priv->clk_can);
> +             if (ret) {
> +                     if (priv->clk_ipg)
> +                             clk_disable_unprepare(priv->clk_ipg);
> +                     goto exit_retcode;

Why don't you add another jump label and jump to that to disable the
ipkg clock?


> +             }
> +     }
> +
>       /* common open */
>       ret = open_candev(dev);
>       if (ret)
> -             return ret;
> +             goto exit_dis_clock;
>  
>       napi_enable(&priv->napi);
>  
> @@ -604,6 +618,12 @@ exit_free_irq:
>  exit_napi_disable:
>       napi_disable(&priv->napi);
>       close_candev(dev);
> +exit_dis_clock:
> +     if (priv->clk_can)
> +             clk_disable_unprepare(priv->clk_can);
> +     if (priv->clk_ipg)
> +             clk_disable_unprepare(priv->clk_ipg);
> +exit_retcode:
>       return ret;
>  }

Marc

-- 
Pengutronix e.K.                  | Marc Kleine-Budde           |
Industrial Linux Solutions        | Phone: +49-231-2826-924     |
Vertretung West/Dortmund          | Fax:   +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686  | http://www.pengutronix.de   |

Attachment: signature.asc
Description: OpenPGP digital signature

_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev

Reply via email to