diff options
Diffstat (limited to 'meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0015-can-rcar_can-support-all-input-clocks.patch')
-rw-r--r-- | meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0015-can-rcar_can-support-all-input-clocks.patch | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0015-can-rcar_can-support-all-input-clocks.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0015-can-rcar_can-support-all-input-clocks.patch new file mode 100644 index 0000000..65f33af --- /dev/null +++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0015-can-rcar_can-support-all-input-clocks.patch @@ -0,0 +1,139 @@ +From 862e2b6af9413b43ef044979b934cab07bfd33e5 Mon Sep 17 00:00:00 2001 +From: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com> +Date: Fri, 1 Aug 2014 01:23:32 +0400 +Subject: [PATCH] can: rcar_can: support all input clocks + +When writing the driver, I didn't give enough attention to the possible sources +of the CAN clock: although the value of the CLKR register was specified by the +platform data, the driver only handled one case, that is CAN clock being +sourced from the clkp1 clock, the same that clocks the whole CAN module. In +order to fix that overlook, we'll have to handle the CAN clock separately from +the peripheral clock (however, clkp1 will be specified for a CAN device only +once)... + +Signed-off-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com> +Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de> +--- + drivers/net/can/rcar_can.c | 42 ++++++++++++++++++++++++++++++++++++------ + 1 file changed, 36 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/can/rcar_can.c b/drivers/net/can/rcar_can.c +index 5268d21..c02fcf3 100644 +--- a/drivers/net/can/rcar_can.c ++++ b/drivers/net/can/rcar_can.c +@@ -87,6 +87,7 @@ struct rcar_can_priv { + struct napi_struct napi; + struct rcar_can_regs __iomem *regs; + struct clk *clk; ++ struct clk *can_clk; + u8 tx_dlc[RCAR_CAN_FIFO_DEPTH]; + u32 tx_head; + u32 tx_tail; +@@ -505,14 +506,20 @@ static int rcar_can_open(struct net_device *ndev) + + err = clk_prepare_enable(priv->clk); + if (err) { +- netdev_err(ndev, "clk_prepare_enable() failed, error %d\n", ++ netdev_err(ndev, "failed to enable periperal clock, error %d\n", + err); + goto out; + } ++ err = clk_prepare_enable(priv->can_clk); ++ if (err) { ++ netdev_err(ndev, "failed to enable CAN clock, error %d\n", ++ err); ++ goto out_clock; ++ } + err = open_candev(ndev); + if (err) { + netdev_err(ndev, "open_candev() failed, error %d\n", err); +- goto out_clock; ++ goto out_can_clock; + } + napi_enable(&priv->napi); + err = request_irq(ndev->irq, rcar_can_interrupt, 0, ndev->name, ndev); +@@ -527,6 +534,8 @@ static int rcar_can_open(struct net_device *ndev) + out_close: + napi_disable(&priv->napi); + close_candev(ndev); ++out_can_clock: ++ clk_disable_unprepare(priv->can_clk); + out_clock: + clk_disable_unprepare(priv->clk); + out: +@@ -565,6 +574,7 @@ static int rcar_can_close(struct net_device *ndev) + rcar_can_stop(ndev); + free_irq(ndev->irq, ndev); + napi_disable(&priv->napi); ++ clk_disable_unprepare(priv->can_clk); + clk_disable_unprepare(priv->clk); + close_candev(ndev); + can_led_event(ndev, CAN_LED_EVENT_STOP); +@@ -715,6 +725,12 @@ static int rcar_can_get_berr_counter(const struct net_device *dev, + return 0; + } + ++static const char * const clock_names[] = { ++ [CLKR_CLKP1] = "clkp1", ++ [CLKR_CLKP2] = "clkp2", ++ [CLKR_CLKEXT] = "can_clk", ++}; ++ + static int rcar_can_probe(struct platform_device *pdev) + { + struct rcar_can_platform_data *pdata; +@@ -722,6 +738,7 @@ static int rcar_can_probe(struct platform_device *pdev) + struct net_device *ndev; + struct resource *mem; + void __iomem *addr; ++ u32 clock_select; + int err = -ENODEV; + int irq; + +@@ -730,6 +747,7 @@ static int rcar_can_probe(struct platform_device *pdev) + dev_err(&pdev->dev, "No platform data provided!\n"); + goto fail; + } ++ clock_select = pdata->clock_select; + + irq = platform_get_irq(pdev, 0); + if (!irq) { +@@ -753,10 +771,22 @@ static int rcar_can_probe(struct platform_device *pdev) + + priv = netdev_priv(ndev); + +- priv->clk = devm_clk_get(&pdev->dev, NULL); ++ priv->clk = devm_clk_get(&pdev->dev, "clkp1"); + if (IS_ERR(priv->clk)) { + err = PTR_ERR(priv->clk); +- dev_err(&pdev->dev, "cannot get clock: %d\n", err); ++ dev_err(&pdev->dev, "cannot get peripheral clock: %d\n", err); ++ goto fail_clk; ++ } ++ ++ if (clock_select >= ARRAY_SIZE(clock_names)) { ++ err = -EINVAL; ++ dev_err(&pdev->dev, "invalid CAN clock selected\n"); ++ goto fail_clk; ++ } ++ priv->can_clk = devm_clk_get(&pdev->dev, clock_names[clock_select]); ++ if (IS_ERR(priv->can_clk)) { ++ err = PTR_ERR(priv->can_clk); ++ dev_err(&pdev->dev, "cannot get CAN clock: %d\n", err); + goto fail_clk; + } + +@@ -765,8 +795,8 @@ static int rcar_can_probe(struct platform_device *pdev) + ndev->flags |= IFF_ECHO; + priv->ndev = ndev; + priv->regs = addr; +- priv->clock_select = pdata->clock_select; +- priv->can.clock.freq = clk_get_rate(priv->clk); ++ priv->clock_select = clock_select; ++ priv->can.clock.freq = clk_get_rate(priv->can_clk); + priv->can.bittiming_const = &rcar_can_bittiming_const; + priv->can.do_set_mode = rcar_can_do_set_mode; + priv->can.do_get_berr_counter = rcar_can_get_berr_counter; +-- +1.9.1 + |